diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..fe71669 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "specs"] + path = specs + url = https://github.com/yunify/qingstor-api-specs.git +[submodule "test/features"] + path = test/features + url = https://github.com/yunify/qingstor-sdk-test-scenarios.git diff --git a/CMake/FindCurl.cmake b/CMake/FindCurl.cmake new file mode 100644 index 0000000..9c1ecf9 --- /dev/null +++ b/CMake/FindCurl.cmake @@ -0,0 +1,33 @@ +# - Find CURL +# Find the native CURL includes and library +# +# CURL_INCLUDE_DIR - where to find curl/curl.h, etc. +# CURL_LIBRARIES - List of libraries when using CURL. +# CURL_FOUND - True if CURL found. + +IF (CURL_INCLUDE_DIR AND CURL_LIBRARIES) + # Already in cache, be silent + SET(CURL_FIND_QUIETLY TRUE) +ENDIF (CURL_INCLUDE_DIR AND CURL_LIBRARIES) + +IF (WIN32) + SET(CURL_NAMES libcurl.lib) + GET_FILENAME_COMPONENT(COMPILER_DIR ${CMAKE_CXX_COMPILER} DIRECTORY) + GET_FILENAME_COMPONENT(VC_DIR ${COMPILER_DIR} DIRECTORY) + FIND_PATH(CURL_INCLUDE_DIR curl/curl.h ${VC_DIR}/include) + FIND_LIBRARY(CURL_LIBRARIES ${CURL_NAMES} ${VC_DIR}/lib) +ELSEIF (APPLE) + SET(CURL_NAMES libcurl.dylib) + FIND_PATH(CURL_INCLUDE_DIR curl/curl.h /usr/local/curl/lib) + FIND_LIBRARY(CURL_LIBRARIES ${CURL_NAMES} /usr/local/lib) +ELSE () + SET(CURL_NAMES libcurl.so) + FIND_PATH(CURL_INCLUDE_DIR curl/curl.h /usr/local/curl/lib) + FIND_LIBRARY(CURL_LIBRARIES ${CURL_NAMES} /usr/local/lib) +ENDIF () + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(curl DEFAULT_MSG CURL_LIBRARIES CURL_INCLUDE_DIR) + +MARK_AS_ADVANCED(CURL_LIBRARIES CURL_INCLUDE_DIR) + \ No newline at end of file diff --git a/CMake/FindOpenSSL.cmake b/CMake/FindOpenSSL.cmake new file mode 100644 index 0000000..2426e29 --- /dev/null +++ b/CMake/FindOpenSSL.cmake @@ -0,0 +1,32 @@ +# - Find OPENSSL +# Find the native OPENSSL includes and library +# +# OPENSSL_INCLUDE_DIR - where to find ssl.h, etc. +# CURL_LIBRARIES - List of libraries when using OPENSSL. +# CURL_FOUND - True if OPENSSL found. + +IF (OPENSSL_INCLUDE_DIR AND OPENSSL_LIBRARIES) + # Already in cache, be silent + SET(OPENSSL_FIND_QUIETLY TRUE) +ENDIF (OPENSSL_INCLUDE_DIR AND OPENSSL_LIBRARIES) + +IF (WIN32) + GET_FILENAME_COMPONENT(COMPILER_DIR ${CMAKE_CXX_COMPILER} DIRECTORY) + GET_FILENAME_COMPONENT(VC_DIR ${COMPILER_DIR} DIRECTORY) + FIND_PATH(OPENSSL_INCLUDE_DIR ssl.h ${VC_DIR}/include/openssl) + FIND_LIBRARY(OPENSSL_CRYPTO_LIBRARIES "libeay32.lib" ${VC_DIR}/lib) + FIND_LIBRARY(OPENSSL_SSL_LIBRARIES "ssleay32.lib" ${VC_DIR}/lib) +ELSEIF (APPLE) + FIND_PATH(OPENSSL_INCLUDE_DIR ssl.h /usr/local/include/openssl) + FIND_LIBRARY(OPENSSL_CRYPTO_LIBRARIES "libcrypto.dylib" /usr/local/lib) + FIND_LIBRARY(OPENSSL_SSL_LIBRARIES "libssl.dylib" /usr/local/lib) +ELSE () + FIND_PATH(OPENSSL_INCLUDE_DIR ssl.h /usr/local/include/openssl /usr/include/openssl) + FIND_LIBRARY(OPENSSL_CRYPTO_LIBRARIES "libcrypto.so" /usr/local/lib) + FIND_LIBRARY(OPENSSL_SSL_LIBRARIES "libssl.so" /usr/local/lib) +ENDIF () + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(openssl DEFAULT_MSG OPENSSL_CRYPTO_LIBRARIES OPENSSL_INCLUDE_DIR) + +MARK_AS_ADVANCED(OPENSSL_CRYPTO_LIBRARIES OPENSSL_INCLUDE_DIR) diff --git a/CMake/Functions.cmake b/CMake/Functions.cmake new file mode 100644 index 0000000..a771b60 --- /dev/null +++ b/CMake/Functions.cmake @@ -0,0 +1,46 @@ +FUNCTION(AUTO_SOURCES RETURN_VALUE PATTERN SOURCE_SUBDIRS) + + IF ("${SOURCE_SUBDIRS}" STREQUAL "RECURSE") + SET(PATH ".") + IF (${ARGC} EQUAL 4) + LIST(GET ARGV 3 PATH) + ENDIF () + ENDIF() + + IF ("${SOURCE_SUBDIRS}" STREQUAL "RECURSE") + UNSET(${RETURN_VALUE}) + FILE(GLOB SUBDIR_FILES "${PATH}/${PATTERN}") + LIST(APPEND ${RETURN_VALUE} ${SUBDIR_FILES}) + + FILE(GLOB SUBDIRS RELATIVE ${PATH} ${PATH}/*) + + FOREACH(DIR ${SUBDIRS}) + IF (IS_DIRECTORY ${PATH}/${DIR}) + IF (NOT "${DIR}" STREQUAL "CMAKEFILES") + FILE(GLOB_RECURSE SUBDIR_FILES "${PATH}/${DIR}/${PATTERN}") + LIST(APPEND ${RETURN_VALUE} ${SUBDIR_FILES}) + ENDIF() + ENDIF() + ENDFOREACH() + ELSE () + FILE(GLOB ${RETURN_VALUE} "${PATTERN}") + + FOREACH (PATH ${SOURCE_SUBDIRS}) + FILE(GLOB SUBDIR_FILES "${PATH}/${PATTERN}") + LIST(APPEND ${RETURN_VALUE} ${SUBDIR_FILES}) + ENDFOREACH(PATH ${SOURCE_SUBDIRS}) + ENDIF () + + IF (${FILTER_OUT}) + LIST(REMOVE_ITEM ${RETURN_VALUE} ${FILTER_OUT}) + ENDIF() + + SET(${RETURN_VALUE} ${${RETURN_VALUE}} PARENT_SCOPE) +ENDFUNCTION(AUTO_SOURCES) + +FUNCTION(CONTAINS_STRING FILE SEARCH RETURN_VALUE) + FILE(STRINGS ${FILE} FILE_CONTENTS REGEX ".*${SEARCH}.*") + IF (FILE_CONTENTS) + SET(${RETURN_VALUE} TRUE PARENT_SCOPE) + ENDIF() +ENDFUNCTION(CONTAINS_STRING) diff --git a/CMake/Options.cmake b/CMake/Options.cmake new file mode 100644 index 0000000..036edd4 --- /dev/null +++ b/CMake/Options.cmake @@ -0,0 +1 @@ +#OPTION(ENABLE_CURL_WIN_CLIENT "using curl on windows" ON) \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..028d222 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,26 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +PROJECT(libQingStor) + +SET(CMAKE_VERBOSE_MAKEFILE ON CACHE STRING "Verbose build." FORCE) + +SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" ${CMAKE_MODULE_PATH}) + +INCLUDE(Functions) +INCLUDE(Options) + +IF (WIN32) + ADD_DEFINITIONS(-DWIN32) +ELSE () + FIND_PACKAGE(OpenSSL REQUIRED) + FIND_PACKAGE(Curl REQUIRED) +ENDIF() + +# add preprocesser macro +ADD_DEFINITIONS(-DCURL_STATICLIB) +ADD_DEFINITIONS(-DYAML_DECLARE_STATIC) + +ADD_SUBDIRECTORY(src lib) + + + diff --git a/LICENSE1 b/LICENSE1 new file mode 100644 index 0000000..f933538 --- /dev/null +++ b/LICENSE1 @@ -0,0 +1,208 @@ +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 2012 Yunify Inc. + +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. \ No newline at end of file diff --git a/LICENSE2 b/LICENSE2 new file mode 100644 index 0000000..399f819 --- /dev/null +++ b/LICENSE2 @@ -0,0 +1,19 @@ +Copyright (c) 2006-2016 Kirill Simonov + +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. \ No newline at end of file diff --git a/NOTICE.txt b/NOTICE.txt new file mode 100644 index 0000000..f40e23e --- /dev/null +++ b/NOTICE.txt @@ -0,0 +1,19 @@ +QingStor SDK for C and C++ +Copyright (C) 2017 Yunify, Inc. or its affiliates. All Rights Reserved. + + This product includes software developed by + Yunify, Inc (http://qingcloud.com//). + +// +--------------------------------------------------------------------------------------------------- +// | THIRD PARTY COMPONENTS +// +--------------------------------------------------------------------------------------------------- +// | +// | This software includes third party software subject to the following copyrights: +// | +// | - YAML parsing and utility functions from LibYAML - Lee Thomason. +// | +// | - JSON parsing and utility functions from JsonCpp - Copyright (c) 2007-2010 Baptiste Lepilleur. +// | +// | The licenses for these third party components are included in LICENSE.txt +// | +// +---------------------------------------------------------------------------------------------------- diff --git a/README.md b/README.md new file mode 100644 index 0000000..0536c26 --- /dev/null +++ b/README.md @@ -0,0 +1,76 @@ +# QingStor SDK for C and C++ + + +The official QingStor SDK for the C and C++ programming language. + +The project is implemented with C++. +It also provides C style interface ( C wrapper for C++ interface ). +Restful API related code in this project is generated by [snips][snips link] (A code generator for RESTful APIs). + +## Getting Started + +### Installation + +Refer to the [Installation Guide][installation guide], and have this SDK installed. + +### Preparation + +Before your start, please go to [QingCloud Console][console link] to create a pair of QingCloud API AccessKey. + +___API AccessKey Example:___ + +``` yaml +access_key_id: 'ACCESS_KEY_ID_EXAMPLE' +secret_access_key: 'SECRET_ACCESS_KEY_EXAMPLE' +``` +### Usage + +Now you are ready to code. You can read the detailed guides in the list below to have a clear understanding. +If you are programing with C++ language, we recommend you to use the modern C++ interface and read `Usage Guide for QingStor C++ style interface`. +And if you are programing with C language, you should chose the C style interface and read `Usage Guide for QingStor style interface`. + +- [Configuration Guide][config guide] +- [Usage Guide for QingStor C style interface][c style usage] +- [Usage Guide for QingStor C++ style interface][cpp style usage] + +Checkout our [RELEASE][release link] and [CHANGELOGS][change logs link] for information about the latest features, bug fixes and new ideas. + +### Running tests: + +Several directories are appended with *tests. After building your project, you can run these executables to ensure everything works properly. +Tests here is mplementated based on [Cucumber test framework][cucumber link]. + +## Reference Documentations + +- [QingStor Documentation][documentation link] +- [QingStor Guide][guide link] +- [QingStor APIs][api doc link] +- [QingStor API Specs][api specs link] +- [QingStor SDK Test Scenarios][sdk test scenarios link] + +## Contributing + +1. Fork it ( https://github.com/yunify/qingstor-sdk-c-and-cpp/fork ) +2. Create your feature branch (`git checkout -b new-feature`) +3. Commit your changes (`git commit -asm 'Add some feature'`) +4. Push to the branch (`git push origin new-feature`) +5. Create a new Pull Request + +## LICENSE + +The Apache License (Version 2.0, January 2004). + +[snips link]: https://github.com/yunify/snips +[installation guide]: docs/installation.md +[console link]: https://console.qingcloud.com/access_keys/ +[c style usage]: docs/sdk_c_style_usage.md +[cpp style usage]: docs/sdk_cpp_style_usage.md +[config guide]: docs/configuration.md +[release link]: https://github.com/yunify/qingstor-sdk-c-and-cpp/releases +[change logs link]: https://github.com/yunify/qingstor-sdk-net/blob/master/CHANGELOGS +[documentation link]: https://docs.qingcloud.com/qingstor/index.html +[guide link]: https://docs.qingcloud.com/qingstor/index.html +[api doc link]: https://docs.qingcloud.com/qingstor/api/index.html +[api specs link]: https://github.com/yunify/qingstor-api-specs +[sdk test scenarios link]: https://github.com/yunify/qingstor-sdk-test-scenarios +[cucumber link]: https://github.com/cucumber/cucumber-cpp diff --git a/code_generate.sh b/code_generate.sh new file mode 100755 index 0000000..44179fc --- /dev/null +++ b/code_generate.sh @@ -0,0 +1,36 @@ + #!/bin/sh + + # generate code + echo "[------- generating code... -------]" + + snips=`which snips` + echo "$snips" + + if [ ! -f $snips ]; then \ + echo "ERROR: Command \"snips\" not found."; \ + fi + sudo $snips -f="./specs/2016-01-06/swagger/api_v2.0.json" -t="./template/header/" -o="./include/" + sudo $snips -f="./specs/2016-01-06/swagger/api_v2.0.json" -t="./template/source/" -o="./src/service" + sudo $snips -f="./specs/2016-01-06/swagger/api_v2.0.json" -t="./template/header_with_c_style/" -o="./include/service_with_c_style/" + sudo $snips -f="./specs/2016-01-06/swagger/api_v2.0.json" -t="./template/source_with_c_style/" -o="./src/service/service_with_c_style/" + + # format code + echo "[------- formating code... -------]" + sudo mv ./include/service_with_c_style/QsList.h ./include/service_with_c_style/QsList_bak + sudo find ./include/ -name "*.h"| xargs sudo indent -npro -kr -i4 -ts4 -sob -l80 -ss -bl -bli 0 + sudo find ./src/service -name "*.cpp" | xargs sudo indent -npro -kr -i4 -ts4 -sob -l80 -ss -bl -bli 0 + sudo find . -name "*~" | xargs sudo rm + sudo astyle -R ./*.cpp ./*.h --delete-empty-lines -n --style=ansi $file + sudo mv ./include/service_with_c_style/QsList_bak ./include/service_with_c_style/QsList.h + # orgnize files + echo "[------- orgnizing files... -------]" + sudo rm -rf ./src/service/Object.cpp + echo "delete file ./src/service/Object.cpp" + sudo rm -rf ./include/Object.h + echo "delete file ./include/Object.h" + sudo mv ./src/service/service_with_c_style/QingStor.cpp ./src/service/service_with_c_style/QingStorCStyle.cpp + echo "rename file QingStorCStyle.cpp " + sudo mv ./include/service_with_c_style/QingStor.h ./include/service_with_c_style/QingStorCStyle.h + echo "rename file QingStorCStyle.h " + + echo "Done" \ No newline at end of file diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 0000000..6eaf637 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,46 @@ +# Configuration Guide + +## Summary + +This SDK uses a structure called "Config" to store and manage configuration. + +Except for Access Key, you can also configure the API endpoint for private cloud usage scenario. All available configurable items are listed in the default configuration file. + +___Default Configuration File:___ + +You can copy the default configuration file to your project directory from [here](https://github.com/yunify/qingstor-sdk-net/blob/master/src/Config), and modify it according to your required. + +``` yaml +# QingStor services configuration + +access_key_id: 'ACCESS_KEY_ID' +secret_access_key: 'SECRET_ACCESS_KEY' + +host: 'qingstor.com' +port: 443 +protocol: 'https' +connection_retries: 3 +timeOutPeriod: 3 +``` + +## Usage + +Just create a config structure instance with your API Access Key, and initialize services you need with Init() function of the target service. + +### Code Snippet + +Create default configuration + +``` c +QsConfig qsConfig; +``` + +Change API endpoint + +``` c +QsConfig qsConfig; +qsConfig.Protoco = "https"; +qsConfig.Host = "api.private.com"; +qsConfig.Port = 4433; +``` + diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..27204d1 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,70 @@ +# Installation Guide + +## Requirement + +To use the QingStor SDK for C and C++, you need: + +* Visual Studio 2013 or later +* OR GNU Compiler Collection (GCC) 4.1.2 or later + * 4GB of RAM + * 4GB of RAM is required to build some of the larger clients. + +Additional Requirements for Linux Systems + +To compile on Linux, you must have the header files (-dev packages) for libcurl, libopenssl. Typically, you'll find the packages in your system's package manager. + +To install these packages on Debian/Ubuntu-based systems +``` bash +$ sudo apt-get install libcurl4-openssl-dev libssl-dev +``` + +To install these packages on Redhat/Fedora-based systems +``` bash +$ sudo yum install libcurl-devel openssl-devel +``` + +To compile on Windows, you must have you must provide the header files and library of openssl, libcurl. + + +## Install from source code + +Clone with Git: + +``` bash +$ git clone https://github.com/yunify/qingstor-sdk-c-and-cpp.git +``` + +You can also download a specified version of zipped source code in the repository [releases page](https://github.com/yunify/qingstor-sdk-c-and-cpp/releases). The zipped source code only contains source code without unit test files. + + +### Creating an Out-of-Source Build (Recommended): +To create an **out-of-source build**: +1. Install CMake and the relevant build tools for your platform. Ensure these are available in your executable path. +2. Create your build directory. Replace BUILD_DIR with your build directory name: + +``` +cd BUILD_DIR +cmake +``` + +You can use the following variations to create your build directory: +* For Auto Make build systems: +`make` + + +To create a **release build**, do one of the following: +* For Auto Make build systems: +``` +cmake -DCMAKE_BUILD_TYPE=Release +make +sudo make install +``` + +To create a **build with C style interface (defaul is off)**, do one of the following: +cmake -DBUILD_C_STYLE_INTERFACE=ON + +## Examples +We provide a sample for C and a sample for C++. The samples show how to use cmake to introduce SDK to build project: +`samples/samples_sdk_c` and `samples/samples_sdk_cpp`. + + diff --git a/docs/sdk_c_style_usage.md b/docs/sdk_c_style_usage.md new file mode 100644 index 0000000..cb4afa7 --- /dev/null +++ b/docs/sdk_c_style_usage.md @@ -0,0 +1,355 @@ +# QingStor Service Usage Guide For C + +Import the QingStor and initialize service with a config, and you are ready to use the initialized service. + +Each API function take a Input struct and return an Output struct. The Input struct consists of request params, request headers, request elements and request body, and the Output holds the HTTP status code, QingStor request ID, response headers, response elements, response body and error ( if error occurred ). + +Every member variable in Input struct is defined for type "Pointer", The user needs to ensure that corresponding memory space for these member variables is vaild when API synchronously blocking. Each API function in SDK is synchronous. All Input struct and custom struct( e.g. "qs_grantee_t" ) should be initialized by corresponding initialization function( e.g. "init_put_bucket_acl_input" adn "init_grantee" ). + +### Code Snippet + +All code using the QingStor SDK and C should have at least the following: + +```c +#include "qingstor/service_with_c_style/QingStorCStyle.h" + +// Global initialization only needs to be initialized once +// Valid log levels are "Verbose","Debug", "Info", "Warning", "Error", "Fatal" and "None".(default value is "None") +qs_init_sdk("/tmp/", LogLevel::Debug, 1); + +// Create qs_context_handle, which is used in every API. +qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + +// Use the sdk +... + +// Release context_hdl +qs_release_service(qs_context_handle context_hdl); + +// Shutdown SDK wide state for the SDK. This method should be called when you are finished using the SDK. +// Do not call any other SDK methods after calling ShutdownSDK. +qs_shutdown_sdk(1); +``` + +List buckets +``` c +qs_list_buckets_output_t output; +qs_list_buckets_input_t input; + +//Initialize the input variable before calling the function +init_list_buckets_input(&input); + +QsError err = qs_list_buckets(&input,&output,context_hdl); +if ( QS_ERR_NO_ERROR != err) +{ + // Print the HTTP status code. + printf("%d\n",output->response_code); +} + +if (QS_ERR_UNEXCEPTED_RESPONSE == err ) +{ + printf("request_id = %s , with detail message : %s\n" , error_info.request_id, error_info.messag); +} + +//Release output the when it is no longer needed. +release_list_buckets_output(&output); +``` + +List objects in the bucket +```c +qs_list_objects_output_t output; +qs_list_objects_input_t input; + +// Initialize the input variable before calling the function +init_list_objects_input(&input); + +// Setting input parameters +int limit = 200; +input->limit =&limit; + +QsError err = qs_list_objects(&input,&output,context_hdl); +if ( QS_ERR_NO_ERROR != err) +{ + // Print the HTTP status code. + // Example: 200 + printf("%d\n",output->response_code); + + // Print the key count. + // Example: 0 + printf("%d\n",output.GetKeys()); +} + +//Release output the when it is no longer needed. +release_list_buckets_output(&output); +``` + +Put ACL of the bucket +```c +qs_put_bucket_acl_input_t input; +qs_put_bucket_acl_output_t output; + +//Initialize the input variable before calling the function. +init_put_bucket_acl_input (&input); + +// define and init acl variable. +qs_acl_t acl; +init_acl (&acl); + +// define and init grantee variable. +qs_grantee_t grantee; +init_grantee (&grantee); + +// fill grantee variable. +grantee.type = "group"; +grantee.name = "QS_ALL_USERS"; + +// fill the grantee field of acl. +acl.grantee = &grantee; +acl.permission = "FULL_CONTROL"; + +// define and init acl list item variable, and fill the content field of acl. +qs_acl_item_t acl_item; +acl_item.content = &acl; + +// init input acl field and append list node (a acl list item) to it. +qs_list_t acllist; +input.acl = &acllist; + +qs_list_init (input.acl); +qs_list_append (&acl_item.node, input.acl); + +QsError err = qs_put_bucket_acl(&input, &output, context_hdl); +if (QS_ERR_NO_ERROR != err) +{ + // Print the HTTP status code. + printf("%d\n",output->response_code); +} + +if (QS_ERR_UNEXCEPTED_RESPONSE == err ) +{ + printf("request_id = %s , with detail message : %s\n" , error_info.request_id, error_info.messag); +} +// Release output the when it is no longer needed. +release_put_bucket_acl_output(&output); +``` + +Put object with key +```c +qs_put_object_input_t input; +qs_put_object_output_t output; + +// Initialize the input variable before calling the function +init_put_object_input(&input); + +// Object content is come from a buffer. +long length = strlen("this is a test"); +input.bodybuf = (char*)malloc( length ); +memcpy(input.bodybuf,"this is a test",length); +input.content_length = &length; +input.bufLength = &length; + +QsError err = qs_put_object(objectKey, &input, &output, context_hdl); +if ( QS_ERR_NO_ERROR != err) +{ + // Print the HTTP status code. + printf("%d\n",output->response_code); +} + +// Release heap memory you've just applied for input. +if(input.bodybuf) +{ + free(input.bodybuf); +} + +if (QS_ERR_UNEXCEPTED_RESPONSE == err ) +{ + printf("request_id = %s , with detail message : %s\n" , error_info.request_id, error_info.messag); +} + +// Release output the when it is no longer needed. +release_put_object_output(&output); +``` + +Delete object with key +```c +qs_delete_object_input_t input; +qs_delete_object_output_t output; + +//Initialize the input variable before calling the function +init_delete_object_input(&input); + +QsError err = qs_delete_object(objectkey, &input, &output, context_hdl); +if ( QS_ERR_NO_ERROR != err) +{ + // Print the HTTP status code. + printf("%d\n",output->response_code); +} + +if (QS_ERR_UNEXCEPTED_RESPONSE == err ) +{ + printf("request_id = %s , with detail message : %s\n" , error_info.request_id, error_info.messag); +} + +//Release output the when it is no longer needed. +release_delete_object_output(&output); +``` + +Initialize Multipart Upload +```c +qs_initiate_multipart_upload_input_t input; +qs_initiate_multipart_upload_output_t output; + +//Initialize the input variable before calling the function +init_initiate_multipart_upload_input(&input); + +QsError err = qs_initiate_multipart_upload(objectkey, &input, &output, context_hdl); + +if ( QS_ERR_NO_ERROR == err) +{ + // Print the HTTP status code. + // Example: 200 + printf("%d\n",output->response_code); + // Print the upload ID. + // Example: "9d37dd6ccee643075ca4e597ad65655c" + printf("%d\n",output.upload_id); +} + +if (QS_ERR_UNEXCEPTED_RESPONSE == err ) +{ + printf("request_id = %s , with detail message : %s\n" , error_info.request_id, error_info.messag); +} + +//Release output the when it is no longer needed. +release_initiate_multipart_upload_output(&output); +``` + +Upload Multipart +```c +// Upload The First Part +qs_upload_multipart_input_t input1; +qs_upload_multipart_output_t output1; + +//Initialize the input variable before calling the function +init_upload_multipart_input(&input1); + +printf(" |this is a Part 1| "); +long length = strlen(" |this is a Part 1| "); +int part_number = 1; +input1.bodybuf = (char *)malloc(length); +input1.bufLength = &length; +input1.content_length = &length; +input1.part_number = &part_number; +input1.upload_id = "9d37dd6ccee643075ca4e597ad65655c"; + +QsError err1 = qs_upload_multipart(objectkey, &input1, &output1, context_hdl); + +if (QS_ERR_NO_ERROR == err1) +{ + // Print the HTTP status code. + // Example: 201 + printf("%d\n",output1->response_code); +} + +if (QS_ERR_UNEXCEPTED_RESPONSE == err ) +{ + printf("request_id = %s , with detail message : %s\n" , error_info.request_id, error_info.messag); +} +// Release heap memory you've just applied for input. +if(input1.bodybuf) +{ + free(input1.bodybuf); +} + +// Release output the when it is no longer needed. +release_upload_multipart_output(&output1); + +// Upload The Second Part +qs_upload_multipart_input_t input2; +qs_upload_multipart_output_t output2; + +//Initialize the input variable before calling the function +init_upload_multipart_input(&input2); + +printf(" |this is a Part 2| "); +long length = strlen(" |this is a Part 2| "); +int part_number = 2; +input2.bodybuf = (char *)malloc(length); +input2.bufLength = &length; +input2.content_length = &length; +input2.part_number = &part_number; +input2.upload_id = "9d37dd6ccee643075ca4e597ad65655c"; + +QsError err2 = qs_upload_multipart(objectkey, &input2, &output2, context_hdl); + +if (QS_ERR_NO_ERROR == err2) +{ + // Print the HTTP status code. + printf("%d\n",output2->response_code); +} + +if (QS_ERR_UNEXCEPTED_RESPONSE == err ) +{ + printf("request_id = %s , with detail message : %s\n" , error_info.request_id, error_info.messag); +} +// Release heap memory you've just applied for input. +if(input2.bodybuf) +{ + free(input2.bodybuf); +} + +// Release output the when it is no longer needed. +release_upload_multipart_output(&output2); +``` + +Complete Multipart Upload +```c +qs_complete_multipart_upload_input_t input; +qs_complete_multipart_upload_output_t output; + +//Initialize the input variable before calling the function +init_complete_multipart_upload_input(&input); + +input.object_parts = &object_parts_list; +input.upload_id = "9d37dd6ccee643075ca4e597ad65655c"; + +QsError err = qs_complete_multipart_upload(objectkey, &input, &output, context_hdl); +if (QS_ERR_NO_ERROR == err) +{ + // Print the HTTP status code. + printf("%d\n",output->response_code); +} + +if (QS_ERR_UNEXCEPTED_RESPONSE == err ) +{ + printf("request_id = %s , with detail message : %s\n" , error_info.request_id, error_info.messag); +} +//Release output the when it is no longer needed. +release_complete_multipart_upload_output(&output); +``` + +Abort Multipart Upload +```c +qs_abort_multipart_upload_input_t input; +qs_abort_multipart_upload_output_t output; + +//Initialize the input variable before calling the function +init_abort_multipart_upload_input(&input); + +input.upload_id = "9d37dd6ccee643075ca4e597ad65655c"; + +QsError err = qs_abort_multipart_upload(objectkey, &input, &output, context_hdl); +if (QS_ERR_NO_ERROR == err) +{ + // Print the HTTP status code. + // Example: 400 + printf("%d\n",output->response_code); +} + +if (QS_ERR_UNEXCEPTED_RESPONSE == err ) +{ + printf("request_id = %s , with detail message : %s\n" , error_info.request_id, error_info.messag); +} +//Release output the when it is no longer needed. +release_abort_multipart_upload_output(&output); +``` + diff --git a/docs/sdk_cpp_style_usage.md b/docs/sdk_cpp_style_usage.md new file mode 100644 index 0000000..ce06a7d --- /dev/null +++ b/docs/sdk_cpp_style_usage.md @@ -0,0 +1,304 @@ +# QingStor Service Usage Guide For C++ + +Import the QingStor and initialize service with a config, and you are ready to use the initialized service. Service only contains one API, and it is "ListBuckets". To use bucket related APIs, you need to initialize a bucket object. + +Each API function take a Input class and return an Output class. The Input class consists of request params, request headers, request elements and request body, and the Output class holds the HTTP status code, QingStor request ID, response headers, response elements, response body and error (if error occurred). + +Each API function in SDK is synchronous. + +### Code Snippet + +All code using the QingStor SDK and C++ should have at least the following: + +```c +#include + +// Global initialization only needs to be initialized once +// Valid log levels are "none","debug", "info", "warn", "error", and "fatal".(default value is "None") +QingStor::SDKOptions sdkOptions; +sdkOptions.logLevel = Debug; +sdkOptions.logPath = "/tmp/"; + +QingStor::InitializeSDK(sdkOptions); + +// Use the sdk +... + +// Shutdown SDK wide state for the SDK. This method should be called when you are finished using the SDK. +// Do not call any other SDK methods after calling ShutdownSDK. +QingStor::ShutdownSDK(options); +``` + +Create the QingStor service and Bucket object with a configuration +```c +// Create QsConfig object , and init it with config info loaded form ConfigPath. +// You can also set up the config configuration item separately. +QingStor::QsConfig qsConfig; +qsConfig.LoadConfigFile("/etc/qingstor/config.yaml"); + +QingStorService qsService(qsConfig); +Bucket qsBucket(qsConfig, "yourbucketname", "yourzone"); +``` + +List buckets +``` c +ListBucketsInput input; +ListBucketsOutput output; + +// You can set +input.SetLimit(200); + +QsError err = qsService.ListBuckets(input, output); +// If the return value of API is "QS_ERR_NO_ERROR", +// means that you have received expected response. +if (QsError::QS_ERR_NO_ERROR == err) +{ + // You can use Output related information + std::vector keys = output.GetKeys(); + printf("Got %d objects\n" ,keys.size()); +} + +// If the return value of API is "QS_ERR_UNEXCEPTED_RESPONSE", +// means that you have received response from QingStor, +// but response is not expected. +// You can to know the specific cause of the mistake. +if (QsError::QS_ERR_UNEXCEPTED_RESPONSE == err) +{ + ResponseErrorInfo errorInfo = output.GetResponseErrInfo(); + printf("request_id = %s , with detail message : %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str()); +} + +``` + +List objects in the bucket +```c + +ListObjectsInput input; +ListObjectsOutput output; + +input.SetLimit(200); + +QsError err = qsBucket.ListObjects(input, output); +if (QsError::QS_ERR_NO_ERROR == err) +{ + // You can use Output related information + std::vector keys = output.GetKeys(); + printf("Got %d objects\n" ,keys.size()); +} + +if (QsError::QS_ERR_UNEXCEPTED_RESPONSE == err) +{ + ResponseErrorInfo errorInfo = output.GetResponseErrInfo(); + printf("request_id = %s , with detail message : %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str()); +} + +``` +Put ACL of the bucket +```c +PutBucketACLInput input; +PutBucketACLOutput output; + +std::vector aclList; +ACLType acl; +GranteeType grantee; +grantee.SetType("group"); +grantee.SetName("QS_ALL_USERS"); +acl.SetGrantee(grantee); +acl.SetPermission("FULL_CONTROL"); +aclList.push_back(acl); +input.SetACL(aclList); + +QsError err = qsBucket.PutBucketACL(input, output); +if (QsError::QS_ERR_NO_ERROR != err) +{ + // Print the HTTP status code. + printf("Got response code : %s",output.GetResponseCode()); +} + +if (QsError::QS_ERR_UNEXCEPTED_RESPONSE == err) +{ + ResponseErrorInfo errorInfo = output.GetResponseErrInfo(); + printf("request_id = %s , with detail message : %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str()); +} +``` + +Put object with key +```c +PutObjectInput input; +PutObjectOutput output; + +// object content is come from a file stream. +std::iostream * = new objectStream(new std::fstream("/tmp/Screenshot.jpg")); +objectStream->seekg(0, objectStream->end); +auto streamSize = objectStream->tellg(); +objectStream->seekg(0, objectStream->beg); +input.SetBody(objectStream); +input.SetContentLength(streamSize); + +QsError err = qsBucket.PutObject(objectKey, input, output); +if (QsError::QS_ERR_NO_ERROR != err) +{ + // Print the HTTP status code. + printf("Got response code : %s",output.GetResponseCode()); +} + +if (QsError::QS_ERR_UNEXCEPTED_RESPONSE == err) +{ + ResponseErrorInfo errorInfo = output.GetResponseErrInfo(); + printf("request_id = %s , with detail message : %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str()); +} + +// release the objectStream +if(objectStream) + delete objectStream; +``` + +Delete object with key +```c +DeleteObjectInput input; +DeleteObjectOutput output; + +QsError err = qsBucket.DeleteObject(objectkey, input, output); +if (QsError::QS_ERR_NO_ERROR != err) +{ + // Print the HTTP status code. + printf("Got response code : %s",output.GetResponseCode()); +} + +if (QsError::QS_ERR_UNEXCEPTED_RESPONSE == err) +{ + ResponseErrorInfo errorInfo = output.GetResponseErrInfo(); + printf("request_id = %s , with detail message : %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str()); +} + +``` +Initialize Multipart Upload +```c +initiateMultipartUpload input; +initiateMultipartUpload output; + +QsError err = qsBucket.InitiateMultipartUpload(objectkey, input, output); +if (QsError::QS_ERR_NO_ERROR == err) +{ + // Print the HTTP status code. + printf("Got response code : %s",output.GetResponseCode()); + // Print the upload ID. + // Example: "9d37dd6ccee643075ca4e597ad65655c" + printf("The upload id is : %s",output.GetUploadID()); +} + +if (QsError::QS_ERR_UNEXCEPTED_RESPONSE == err) +{ + ResponseErrorInfo errorInfo = output.GetResponseErrInfo(); + printf("request_id = %s , with detail message : %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str()); +} +``` +Upload Multipart +```c +// Upload the first part +UploadMultipartInput inputPart1; +UploadMultipartOutput outputPart1; + +std::iostream* objectStream1 = new std::fstream(filePath1)); +objectStream1->seekg(0, objectStream1->end); +size_t streamSize1 = objectStream1->tellg(); +objectStream1->seekg(0, objectStream1->beg); +inputPart1.SetBody(objectStream1); +inputPart1.SetContentLength(streamSize1); +inputPart1.SetPartNumber(1); +inputPart1.SetUploadID("9d37dd6ccee643075ca4e597ad65655c"); +QsError err1 = qsBucket.UploadMultipart(objectkey, inputPart1, outputPart1); +if (QsError::QS_ERR_NO_ERROR == err1) +{ + // Print the HTTP status code. + printf("Got response code : %s",output.GetResponseCode()); +} + +if (QsError::QS_ERR_UNEXCEPTED_RESPONSE == err) +{ + ResponseErrorInfo errorInfo = output.GetResponseErrInfo(); + printf("request_id = %s , with detail message : %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str()); +} + +// release the objectStream +if(objectStream1) + delete objectStream1; + +// Upload the second part +UploadMultipartInput inputPart2; +UploadMultipartOutput outputPart2; + +std::iostream* objectStream2 = new std::fstream(filePath2)); +objectStream2->seekg(0, objectStream2->end); +size_t streamSize2 = objectStream2->tellg(); +objectStream2->seekg(0, objectStream2->beg); +inputPart2.SetBody(objectStream2); +inputPart2.SetContentLength(streamSize2); +inputPart2.SetPartNumber(2); +inputPart2.SetUploadID("9d37dd6ccee643075ca4e597ad65655c"); + +QsError err2 = qsBucket.UploadMultipart(objectkey, inputPart2, outputPart2); +if (QsError::QS_ERR_NO_ERROR == err2) +{ + // Print the HTTP status code. + printf("Got response code : %s",output.GetResponseCode()); +} + +if (QsError::QS_ERR_UNEXCEPTED_RESPONSE == err) +{ + ResponseErrorInfo errorInfo = output.GetResponseErrInfo(); + printf("request_id = %s , with detail message : %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str()); +} +// release the objectStream +if(objectStream2) + delete objectStream2; +``` + +Complete Multipart Upload +```c +std::vector objectParts; + +ObjectPartType part1,part2; +part1.SetPartNumber(1); +part2.SetPartNumber(2); +objectParts.push_back(part1); +objectParts.push_back(part2); + +CompleteMultipartUploadInput input; +CompleteMultipartUploadOutput output; +input.SetUploadID("9d37dd6ccee643075ca4e597ad65655c"); +input.SetObjectParts(objectParts); + +QsError err = qsBucket.CompleteMultipartUpload(objectkey, input, output); +if (QsError::QS_ERR_NO_ERROR == err) +{ + // Print the HTTP status code. + printf("Got response code : %s",output.GetResponseCode()); +} + +if (QsError::QS_ERR_UNEXCEPTED_RESPONSE == err) +{ + ResponseErrorInfo errorInfo = output.GetResponseErrInfo(); + printf("request_id = %s , with detail message : %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str()); +} +``` + +Abort Multipart Upload +```c +AbortMultipartUploadInput input; +AbortMultipartUploadOutput output; +input.SetUploadID("9d37dd6ccee643075ca4e597ad65655c"); + +QsError err = qsBucket.AbortMultipartUpload(objectkey, input, output); +if (QsError::QS_ERR_NO_ERROR == err) +{ + // Print the HTTP status code. + printf("Got response code : %s",output.GetResponseCode()); +} + +if (QsError::QS_ERR_UNEXCEPTED_RESPONSE == err) +{ + ResponseErrorInfo errorInfo = output.GetResponseErrInfo(); + printf("request_id = %s , with detail message : %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str()); +} +``` \ No newline at end of file diff --git a/include/Bucket.h b/include/Bucket.h new file mode 100644 index 0000000..70f8343 --- /dev/null +++ b/include/Bucket.h @@ -0,0 +1,4136 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include +#include +#include +#include "QsSdkOption.h" +#include "Types.h" +#include "QsErrors.h" +#include "QsConfig.h" + +#ifdef BUILD_C_STYLE_INTERFACE +#include "service_with_c_style/QingStorCStyle.h" +#endif // BUILD_C_STYLE_INTERFACE + +#define BASIC_FLAG 0x0 +// Limits results to buckets that in the location'flag +#define SETTING_INPUT_LIST_BUCKETS_LOCATION_FLAG 0x1 + +// Buckets information'flag +#define SETTING_OUTPUT_LIST_BUCKETS_BUCKETS_FLAG 0x1 + +// Bucket count'flag +#define SETTING_OUTPUT_LIST_BUCKETS_COUNT_FLAG 0x2 + +// Object MD5sum'flag +#define SETTING_INPUT_DELETE_MULTIPLE_OBJECTS_CONTENT_MD5_FLAG 0x1 + +// A list of keys to delete'flag +#define SETTING_INPUT_DELETE_MULTIPLE_OBJECTS_OBJECTS_FLAG 0x2 + +// Whether to return the list of deleted objects'flag +#define SETTING_INPUT_DELETE_MULTIPLE_OBJECTS_QUIET_FLAG 0x4 + +// Error messages'flag +#define SETTING_OUTPUT_DELETE_MULTIPLE_OBJECTS_ERRORS_FLAG 0x1 + +// List of deleted objects'flag +#define SETTING_OUTPUT_DELETE_MULTIPLE_OBJECTS_DELETED_FLAG 0x2 + +// Bucket ACL rules'flag +#define SETTING_OUTPUT_GET_BUCKET_ACL_ACL_FLAG 0x1 + +// Bucket owner'flag +#define SETTING_OUTPUT_GET_BUCKET_ACL_OWNER_FLAG 0x2 + +// Bucket CORS rules'flag +#define SETTING_OUTPUT_GET_BUCKET_CORS_CORS_RULES_FLAG 0x1 + +// Source site url'flag +#define SETTING_OUTPUT_GET_BUCKET_EXTERNAL_MIRROR_SOURCE_SITE_FLAG 0x1 + +// Bucket policy statement'flag +#define SETTING_OUTPUT_GET_BUCKET_POLICY_STATEMENT_FLAG 0x1 + +// QingCloud Zone ID'flag +#define SETTING_OUTPUT_GET_BUCKET_STATISTICS_LOCATION_FLAG 0x1 + +// Bucket name'flag +#define SETTING_OUTPUT_GET_BUCKET_STATISTICS_NAME_FLAG 0x2 + +// Bucket storage size'flag +#define SETTING_OUTPUT_GET_BUCKET_STATISTICS_SIZE_FLAG 0x4 + +// Bucket status'flag +// Status's available values: active, suspended +#define SETTING_OUTPUT_GET_BUCKET_STATISTICS_STATUS_FLAG 0x8 + +// URL to access the bucket'flag +#define SETTING_OUTPUT_GET_BUCKET_STATISTICS_URL_FLAG 0x10 + +// Objects count in the bucket'flag +#define SETTING_OUTPUT_GET_BUCKET_STATISTICS_COUNT_FLAG 0x20 + +// Bucket created time'flag +#define SETTING_OUTPUT_GET_BUCKET_STATISTICS_CREATED_FLAG 0x40 + +// Limit results returned from the first key after key_marker sorted by alphabetical order'flag +#define SETTING_INPUT_LIST_MULTIPART_UPLOADS_KEY_MARKER_FLAG 0x1 + +// Limit results returned from the first uploading segment after upload_id_marker sorted by the time of upload_id'flag +#define SETTING_INPUT_LIST_MULTIPART_UPLOADS_UPLOAD_ID_MARKER_FLAG 0x2 + +// Results count limit'flag +#define SETTING_INPUT_LIST_MULTIPART_UPLOADS_LIMIT_FLAG 0x4 + +// Limits results to keys that begin with the prefix'flag +#define SETTING_INPUT_LIST_MULTIPART_UPLOADS_PREFIX_FLAG 0x8 + +// Put all keys that share a common prefix into a list'flag +#define SETTING_INPUT_LIST_MULTIPART_UPLOADS_DELIMITER_FLAG 0x10 + +// The last key in uploads list'flag +#define SETTING_OUTPUT_LIST_MULTIPART_UPLOADS_NEXT_KEY_MARKER_FLAG 0x1 + +// Delimiter that specified in request parameters'flag +#define SETTING_OUTPUT_LIST_MULTIPART_UPLOADS_DELIMITER_FLAG 0x2 + +// The last upload_id in uploads list'flag +#define SETTING_OUTPUT_LIST_MULTIPART_UPLOADS_NEXT_UPLOAD_ID_MARKER_FLAG 0x4 + +// Prefix that specified in request parameters'flag +#define SETTING_OUTPUT_LIST_MULTIPART_UPLOADS_PREFIX_FLAG 0x8 + +// Bucket name'flag +#define SETTING_OUTPUT_LIST_MULTIPART_UPLOADS_NAME_FLAG 0x10 + +// Multipart uploads'flag +#define SETTING_OUTPUT_LIST_MULTIPART_UPLOADS_UPLOADS_FLAG 0x20 + +// Limit that specified in request parameters'flag +#define SETTING_OUTPUT_LIST_MULTIPART_UPLOADS_LIMIT_FLAG 0x40 + +// Other object keys that share common prefixes'flag +#define SETTING_OUTPUT_LIST_MULTIPART_UPLOADS_COMMON_PREFIXES_FLAG 0x80 + +// Marker that specified in request parameters'flag +#define SETTING_OUTPUT_LIST_MULTIPART_UPLOADS_MARKER_FLAG 0x100 + +// Limits results to keys that begin with the prefix'flag +#define SETTING_INPUT_LIST_OBJECTS_PREFIX_FLAG 0x1 + +// Put all keys that share a common prefix into a list'flag +#define SETTING_INPUT_LIST_OBJECTS_DELIMITER_FLAG 0x2 + +// Limit results to keys that start at this marker'flag +#define SETTING_INPUT_LIST_OBJECTS_MARKER_FLAG 0x4 + +// Results count limit'flag +#define SETTING_INPUT_LIST_OBJECTS_LIMIT_FLAG 0x8 + +// The last key in keys list'flag +#define SETTING_OUTPUT_LIST_OBJECTS_NEXT_MARKER_FLAG 0x1 + +// Prefix that specified in request parameters'flag +#define SETTING_OUTPUT_LIST_OBJECTS_PREFIX_FLAG 0x2 + +// Bucket name'flag +#define SETTING_OUTPUT_LIST_OBJECTS_NAME_FLAG 0x4 + +// Bucket owner'flag +#define SETTING_OUTPUT_LIST_OBJECTS_OWNER_FLAG 0x8 + +// Limit that specified in request parameters'flag +#define SETTING_OUTPUT_LIST_OBJECTS_LIMIT_FLAG 0x10 + +// Delimiter that specified in request parameters'flag +#define SETTING_OUTPUT_LIST_OBJECTS_DELIMITER_FLAG 0x20 + +// Object keys'flag +#define SETTING_OUTPUT_LIST_OBJECTS_KEYS_FLAG 0x40 + +// Other object keys that share common prefixes'flag +#define SETTING_OUTPUT_LIST_OBJECTS_COMMON_PREFIXES_FLAG 0x80 + +// Marker that specified in request parameters'flag +#define SETTING_OUTPUT_LIST_OBJECTS_MARKER_FLAG 0x100 + +// Bucket ACL rules'flag +#define SETTING_INPUT_PUT_BUCKET_ACL_ACL_FLAG 0x1 + +// Bucket CORS rules'flag +#define SETTING_INPUT_PUT_BUCKET_CORS_CORS_RULES_FLAG 0x1 + +// Source site url'flag +#define SETTING_INPUT_PUT_BUCKET_EXTERNAL_MIRROR_SOURCE_SITE_FLAG 0x1 + +// Bucket policy statement'flag +#define SETTING_INPUT_PUT_BUCKET_POLICY_STATEMENT_FLAG 0x1 + +// Object multipart upload ID'flag +#define SETTING_INPUT_ABORT_MULTIPART_UPLOAD_UPLOAD_ID_FLAG 0x1 + +// Object multipart upload ID'flag +#define SETTING_INPUT_COMPLETE_MULTIPART_UPLOAD_UPLOAD_ID_FLAG 0x1 + +// Encryption key of the object'flag +#define SETTING_INPUT_COMPLETE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_KEY_FLAG 0x2 + +// MD5sum of encryption key'flag +#define SETTING_INPUT_COMPLETE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG 0x4 + +// MD5sum of the object part'flag +#define SETTING_INPUT_COMPLETE_MULTIPART_UPLOAD_ETAG_FLAG 0x8 + +// Encryption algorithm of the object'flag +#define SETTING_INPUT_COMPLETE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG 0x10 + +// Object parts'flag +#define SETTING_INPUT_COMPLETE_MULTIPART_UPLOAD_OBJECT_PARTS_FLAG 0x20 + +// Encryption algorithm of the object'flag +#define SETTING_OUTPUT_COMPLETE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG 0x1 + +// Specified the Cache-Control response header'flag +#define SETTING_INPUT_GET_OBJECT_RESPONSE_CACHE_CONTROL_FLAG 0x1 + +// Specified the Content-Type response header'flag +#define SETTING_INPUT_GET_OBJECT_RESPONSE_CONTENT_TYPE_FLAG 0x2 + +// Specified the Content-Language response header'flag +#define SETTING_INPUT_GET_OBJECT_RESPONSE_CONTENT_LANGUAGE_FLAG 0x4 + +// Specified the Content-Encoding response header'flag +#define SETTING_INPUT_GET_OBJECT_RESPONSE_CONTENT_ENCODING_FLAG 0x8 + +// Specified the Content-Disposition response header'flag +#define SETTING_INPUT_GET_OBJECT_RESPONSE_CONTENT_DISPOSITION_FLAG 0x10 + +// Specified the Expires response header'flag +#define SETTING_INPUT_GET_OBJECT_RESPONSE_EXPIRES_FLAG 0x20 + +// Encryption algorithm of the object'flag +#define SETTING_INPUT_GET_OBJECT_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG 0x40 + +// Encryption key of the object'flag +#define SETTING_INPUT_GET_OBJECT_X_QS_ENCRYPTION_CUSTOMER_KEY_FLAG 0x80 + +// MD5sum of encryption key'flag +#define SETTING_INPUT_GET_OBJECT_X_QS_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG 0x100 + +// Specified range of the object'flag +#define SETTING_INPUT_GET_OBJECT_RANGE_FLAG 0x200 + +// Check whether the object has been modified'flag +#define SETTING_INPUT_GET_OBJECT_IF_MODIFIED_SINCE_FLAG 0x400 + +// Check whether the object has not been modified'flag +#define SETTING_INPUT_GET_OBJECT_IF_UNMODIFIED_SINCE_FLAG 0x800 + +// Check whether the ETag matches'flag +#define SETTING_INPUT_GET_OBJECT_IF_MATCH_FLAG 0x1000 + +// Check whether the ETag does not match'flag +#define SETTING_INPUT_GET_OBJECT_IF_NONE_MATCH_FLAG 0x2000 + +// The Content-Language entity header is used to describe the language(s) intended for the audience.'flag +#define SETTING_OUTPUT_GET_OBJECT_CONTENT_LANGUAGE_FLAG 0x1 + +// The Content-Type entity header is used to indicate the media type of the resource.'flag +#define SETTING_OUTPUT_GET_OBJECT_CONTENT_TYPE_FLAG 0x2 + +// The Cache-Control general-header field is used to specify directives for caching mechanisms in both requests and responses.'flag +#define SETTING_OUTPUT_GET_OBJECT_CACHE_CONTROL_FLAG 0x4 + +// Object content length'flag +#define SETTING_OUTPUT_GET_OBJECT_CONTENT_LENGTH_FLAG 0x8 + +// MD5sum of the object'flag +#define SETTING_OUTPUT_GET_OBJECT_ETAG_FLAG 0x10 + +// In a multipart/form-data body, the HTTP Content-Disposition general header is a header that can be used on the subpart of a multipart body to give information about the field it applies to.'flag +#define SETTING_OUTPUT_GET_OBJECT_CONTENT_DISPOSITION_FLAG 0x20 + +// Range of response data content'flag +#define SETTING_OUTPUT_GET_OBJECT_CONTENT_RANGE_FLAG 0x40 + +// The Expires header contains the date/time after which the response is considered stale.'flag +#define SETTING_OUTPUT_GET_OBJECT_EXPIRES_FLAG 0x80 + +// Encryption algorithm of the object'flag +#define SETTING_OUTPUT_GET_OBJECT_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG 0x100 + +// The Content-Encoding entity header is used to compress the media-type.'flag +#define SETTING_OUTPUT_GET_OBJECT_CONTENT_ENCODING_FLAG 0x200 + +#define SETTING_OUTPUT_GET_OBJECT_LAST_MODIFIED_FLAG 0x400 + +// Check whether the object has been modified'flag +#define SETTING_INPUT_HEAD_OBJECT_IF_MODIFIED_SINCE_FLAG 0x1 + +// Check whether the object has not been modified'flag +#define SETTING_INPUT_HEAD_OBJECT_IF_UNMODIFIED_SINCE_FLAG 0x2 + +// Check whether the ETag matches'flag +#define SETTING_INPUT_HEAD_OBJECT_IF_MATCH_FLAG 0x4 + +// Check whether the ETag does not match'flag +#define SETTING_INPUT_HEAD_OBJECT_IF_NONE_MATCH_FLAG 0x8 + +// Encryption algorithm of the object'flag +#define SETTING_INPUT_HEAD_OBJECT_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG 0x10 + +// Encryption key of the object'flag +#define SETTING_INPUT_HEAD_OBJECT_X_QS_ENCRYPTION_CUSTOMER_KEY_FLAG 0x20 + +// MD5sum of encryption key'flag +#define SETTING_INPUT_HEAD_OBJECT_X_QS_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG 0x40 + +// MD5sum of the object'flag +#define SETTING_OUTPUT_HEAD_OBJECT_ETAG_FLAG 0x1 + +#define SETTING_OUTPUT_HEAD_OBJECT_LAST_MODIFIED_FLAG 0x2 + +// Encryption algorithm of the object'flag +#define SETTING_OUTPUT_HEAD_OBJECT_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG 0x4 + +// Object content length'flag +#define SETTING_OUTPUT_HEAD_OBJECT_CONTENT_LENGTH_FLAG 0x8 + +// Object content type'flag +#define SETTING_OUTPUT_HEAD_OBJECT_CONTENT_TYPE_FLAG 0x10 + +// Specified the Content-Language response header'flag +#define SETTING_INPUT_IMAGE_PROCESS_RESPONSE_CONTENT_LANGUAGE_FLAG 0x1 + +// Specified the Content-Encoding response header'flag +#define SETTING_INPUT_IMAGE_PROCESS_RESPONSE_CONTENT_ENCODING_FLAG 0x2 + +// Specified the Content-Disposition response header'flag +#define SETTING_INPUT_IMAGE_PROCESS_RESPONSE_CONTENT_DISPOSITION_FLAG 0x4 + +// Image process action'flag +#define SETTING_INPUT_IMAGE_PROCESS_ACTION_FLAG 0x8 + +// Specified the Expires response header'flag +#define SETTING_INPUT_IMAGE_PROCESS_RESPONSE_EXPIRES_FLAG 0x10 + +// Specified the Cache-Control response header'flag +#define SETTING_INPUT_IMAGE_PROCESS_RESPONSE_CACHE_CONTROL_FLAG 0x20 + +// Specified the Content-Type response header'flag +#define SETTING_INPUT_IMAGE_PROCESS_RESPONSE_CONTENT_TYPE_FLAG 0x40 + +// Check whether the object has been modified'flag +#define SETTING_INPUT_IMAGE_PROCESS_IF_MODIFIED_SINCE_FLAG 0x80 + +// Object content length'flag +#define SETTING_OUTPUT_IMAGE_PROCESS_CONTENT_LENGTH_FLAG 0x1 + +// Object content type'flag +#define SETTING_INPUT_INITIATE_MULTIPART_UPLOAD_CONTENT_TYPE_FLAG 0x1 + +// Encryption algorithm of the object'flag +#define SETTING_INPUT_INITIATE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG 0x2 + +// Encryption key of the object'flag +#define SETTING_INPUT_INITIATE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_KEY_FLAG 0x4 + +// MD5sum of encryption key'flag +#define SETTING_INPUT_INITIATE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG 0x8 + +// Encryption algorithm of the object'flag +#define SETTING_OUTPUT_INITIATE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG 0x1 + +// Bucket name'flag +#define SETTING_OUTPUT_INITIATE_MULTIPART_UPLOAD_BUCKET_FLAG 0x2 + +// Object key'flag +#define SETTING_OUTPUT_INITIATE_MULTIPART_UPLOAD_KEY_FLAG 0x4 + +// Object multipart upload ID'flag +#define SETTING_OUTPUT_INITIATE_MULTIPART_UPLOAD_UPLOAD_ID_FLAG 0x8 + +// Object multipart upload ID'flag +#define SETTING_INPUT_LIST_MULTIPART_UPLOAD_ID_FLAG 0x1 + +// Object multipart upload part number'flag +#define SETTING_INPUT_LIST_MULTIPART_PART_NUMBER_MARKER_FLAG 0x2 + +// Limit results count'flag +#define SETTING_INPUT_LIST_MULTIPART_LIMIT_FLAG 0x4 + +// Object multipart count'flag +#define SETTING_OUTPUT_LIST_MULTIPART_COUNT_FLAG 0x1 + +// Object parts'flag +#define SETTING_OUTPUT_LIST_MULTIPART_OBJECT_PARTS_FLAG 0x2 + +// Request origin'flag +#define SETTING_INPUT_OPTIONS_OBJECT_ORIGIN_FLAG 0x1 + +// Request method'flag +#define SETTING_INPUT_OPTIONS_OBJECT_ACCESS_CONTROL_REQUEST_METHOD_FLAG 0x2 + +// Request headers'flag +#define SETTING_INPUT_OPTIONS_OBJECT_ACCESS_CONTROL_REQUEST_HEADERS_FLAG 0x4 + +// Allowed headers'flag +#define SETTING_OUTPUT_OPTIONS_OBJECT_ACCESS_CONTROL_ALLOW_HEADERS_FLAG 0x1 + +// Allowed methods'flag +#define SETTING_OUTPUT_OPTIONS_OBJECT_ACCESS_CONTROL_ALLOW_METHODS_FLAG 0x2 + +// Allowed origin'flag +#define SETTING_OUTPUT_OPTIONS_OBJECT_ACCESS_CONTROL_ALLOW_ORIGIN_FLAG 0x4 + +// Expose headers'flag +#define SETTING_OUTPUT_OPTIONS_OBJECT_ACCESS_CONTROL_EXPOSE_HEADERS_FLAG 0x8 + +// Max age'flag +#define SETTING_OUTPUT_OPTIONS_OBJECT_ACCESS_CONTROL_MAX_AGE_FLAG 0x10 + +// Encryption algorithm of the object'flag +#define SETTING_INPUT_PUT_OBJECT_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG 0x1 + +// MD5sum of encryption key'flag +#define SETTING_INPUT_PUT_OBJECT_X_QS_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG 0x2 + +// Copy source, format (//)'flag +#define SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_FLAG 0x4 + +// Check whether the copy source matches'flag +#define SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_IF_MATCH_FLAG 0x8 + +// Fetch source, should be a valid url'flag +#define SETTING_INPUT_PUT_OBJECT_X_QS_FETCH_SOURCE_FLAG 0x10 + +// Object content size'flag +#define SETTING_INPUT_PUT_OBJECT_CONTENT_LENGTH_FLAG 0x20 + +// Object MD5sum'flag +#define SETTING_INPUT_PUT_OBJECT_CONTENT_MD5_FLAG 0x40 + +// Used to indicate that particular server behaviors are required by the client'flag +#define SETTING_INPUT_PUT_OBJECT_EXPECT_FLAG 0x80 + +// Check whether the copy source has been modified'flag +#define SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_IF_MODIFIED_SINCE_FLAG 0x100 + +// Check whether the copy source does not match'flag +#define SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_IF_NONE_MATCH_FLAG 0x200 + +// Encryption key of the object'flag +#define SETTING_INPUT_PUT_OBJECT_X_QS_ENCRYPTION_CUSTOMER_KEY_FLAG 0x400 + +// Encryption algorithm of the object'flag +#define SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG 0x800 + +// Move source, format (//)'flag +#define SETTING_INPUT_PUT_OBJECT_X_QS_MOVE_SOURCE_FLAG 0x1000 + +// Object content type'flag +#define SETTING_INPUT_PUT_OBJECT_CONTENT_TYPE_FLAG 0x2000 + +// Check whether the copy source has not been modified'flag +#define SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_IF_UNMODIFIED_SINCE_FLAG 0x4000 + +// Encryption key of the object'flag +#define SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_ENCRYPTION_CUSTOMER_KEY_FLAG 0x8000 + +// MD5sum of encryption key'flag +#define SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG 0x10000 + +// Check whether fetch target object has not been modified'flag +#define SETTING_INPUT_PUT_OBJECT_X_QS_FETCH_IF_UNMODIFIED_SINCE_FLAG 0x20000 + +// Encryption algorithm of the object'flag +#define SETTING_OUTPUT_PUT_OBJECT_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG 0x1 + +// MD5sum of the object'flag +#define SETTING_OUTPUT_PUT_OBJECT_ETAG_FLAG 0x2 + +// Object multipart upload ID'flag +#define SETTING_INPUT_UPLOAD_MULTIPART_UPLOAD_ID_FLAG 0x1 + +// Object multipart upload part number'flag +#define SETTING_INPUT_UPLOAD_MULTIPART_PART_NUMBER_FLAG 0x2 + +// Copy source, format (//)'flag +#define SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_FLAG 0x4 + +// Check whether the copy source has been modified since the specified date'flag +#define SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_IF_MODIFIED_SINCE_FLAG 0x8 + +// Check whether the Etag of copy source does not matches the specified value'flag +#define SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_IF_NONE_MATCH_FLAG 0x10 + +// Object multipart content length'flag +#define SETTING_INPUT_UPLOAD_MULTIPART_CONTENT_LENGTH_FLAG 0x20 + +// Encryption key of the object'flag +#define SETTING_INPUT_UPLOAD_MULTIPART_X_QS_ENCRYPTION_CUSTOMER_KEY_FLAG 0x40 + +// Specify range of the source object'flag +#define SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_RANGE_FLAG 0x80 + +// Check whether the Etag of copy source matches the specified value'flag +#define SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_IF_MATCH_FLAG 0x100 + +// Encryption key of the object'flag +#define SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_ENCRYPTION_CUSTOMER_KEY_FLAG 0x200 + +// Object multipart content MD5sum'flag +#define SETTING_INPUT_UPLOAD_MULTIPART_CONTENT_MD5_FLAG 0x400 + +// Encryption algorithm of the object'flag +#define SETTING_INPUT_UPLOAD_MULTIPART_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG 0x800 + +// Encryption algorithm of the object'flag +#define SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG 0x1000 + +// MD5sum of encryption key'flag +#define SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG 0x2000 + +// MD5sum of encryption key'flag +#define SETTING_INPUT_UPLOAD_MULTIPART_X_QS_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG 0x4000 + +// Check whether the copy source has not been unmodified since the specified date'flag +#define SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_IF_UNMODIFIED_SINCE_FLAG 0x8000 + +// Range of response data content'flag +#define SETTING_OUTPUT_UPLOAD_MULTIPART_X_QS_CONTENT_COPY_RANGE_FLAG 0x1 + +// Encryption algorithm of the object'flag +#define SETTING_OUTPUT_UPLOAD_MULTIPART_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG 0x2 + +// MD5sum of the object'flag +#define SETTING_OUTPUT_UPLOAD_MULTIPART_ETAG_FLAG 0x4 + +namespace QingStor +{ +// +-------------------------------------------------------------------- +// | InputClassHeader +// +-------------------------------------------------------------------- +// DeleteBucketInput presents input for DeleteBucket. +typedef QsInput DeleteBucketInput; +// DeleteBucketCORSInput presents input for DeleteBucketCORS. +typedef QsInput DeleteBucketCORSInput; +// DeleteBucketExternalMirrorInput presents input for DeleteBucketExternalMirror. +typedef QsInput DeleteBucketExternalMirrorInput; +// DeleteBucketPolicyInput presents input for DeleteBucketPolicy. +typedef QsInput DeleteBucketPolicyInput; +// DeleteMultipleObjectsInput presents input for DeleteMultipleObjects. +class QS_SDK_API DeleteMultipleObjectsInput:public QsInput +{ +public: + DeleteMultipleObjectsInput() + { + }; + + inline bool CheckIfInputIsVaild() + { + int tmpFlag = + BASIC_FLAG | + SETTING_INPUT_DELETE_MULTIPLE_OBJECTS_CONTENT_MD5_FLAG | + SETTING_INPUT_DELETE_MULTIPLE_OBJECTS_OBJECTS_FLAG; + return (tmpFlag == (tmpFlag & m_settingFlag)); + }; + // Object MD5sum + + inline void SetContentMD5(std::string ContentMD5) + { + m_settingFlag |= + SETTING_INPUT_DELETE_MULTIPLE_OBJECTS_CONTENT_MD5_FLAG; + m_ContentMD5 = ContentMD5; + }; + + inline std::string GetContentMD5() + { + return m_ContentMD5; + }; + + // A list of keys to delete +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetObjects(qs_list_t * objects) + { + qs_key_item_t *item; + qs_list_for_each_entry(qs_key_item_t, item, objects) + { + m_Objects.push_back(*item->content); + } + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetObjects(std::vector < KeyType > Objects) + { + m_settingFlag |= SETTING_INPUT_DELETE_MULTIPLE_OBJECTS_OBJECTS_FLAG; + m_Objects = Objects; + }; + + inline std::vector < KeyType > GetObjects() + { + return m_Objects; + }; + // Whether to return the list of deleted objects +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetQuiet(int *quiet) + { + m_Quiet = quiet; + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetQuiet(bool Quiet) + { + m_settingFlag |= SETTING_INPUT_DELETE_MULTIPLE_OBJECTS_QUIET_FLAG; + m_Quiet = Quiet; + }; + + inline bool GetQuiet() + { + return m_Quiet; + }; + +private: + // Object MD5sum + std::string m_ContentMD5; // Required + + // A list of keys to delete + + std::vector < KeyType > m_Objects; // Required + + // Whether to return the list of deleted objects + bool m_Quiet; + +}; +// GetBucketACLInput presents input for GetBucketACL. +typedef QsInput GetBucketACLInput; +// GetBucketCORSInput presents input for GetBucketCORS. +typedef QsInput GetBucketCORSInput; +// GetBucketExternalMirrorInput presents input for GetBucketExternalMirror. +typedef QsInput GetBucketExternalMirrorInput; +// GetBucketPolicyInput presents input for GetBucketPolicy. +typedef QsInput GetBucketPolicyInput; +// GetBucketStatisticsInput presents input for GetBucketStatistics. +typedef QsInput GetBucketStatisticsInput; +// HeadBucketInput presents input for HeadBucket. +typedef QsInput HeadBucketInput; +// ListMultipartUploadsInput presents input for ListMultipartUploads. +class QS_SDK_API ListMultipartUploadsInput:public QsInput +{ +public: + ListMultipartUploadsInput() + { + }; + + inline bool CheckIfInputIsVaild() + { + int tmpFlag = BASIC_FLAG; + return (tmpFlag == (tmpFlag & m_settingFlag)); + }; + // Put all keys that share a common prefix into a list + + inline void SetDelimiter(std::string Delimiter) + { + m_settingFlag |= + SETTING_INPUT_LIST_MULTIPART_UPLOADS_DELIMITER_FLAG; + m_Delimiter = Delimiter; + }; + + inline std::string GetDelimiter() + { + return m_Delimiter; + }; + // Limit results returned from the first key after key_marker sorted by alphabetical order + + inline void SetKeyMarker(std::string KeyMarker) + { + m_settingFlag |= + SETTING_INPUT_LIST_MULTIPART_UPLOADS_KEY_MARKER_FLAG; + m_KeyMarker = KeyMarker; + }; + + inline std::string GetKeyMarker() + { + return m_KeyMarker; + }; + // Results count limit + + inline void SetLimit(int Limit) + { + m_settingFlag |= SETTING_INPUT_LIST_MULTIPART_UPLOADS_LIMIT_FLAG; + m_Limit = Limit; + }; + + inline int GetLimit() + { + return m_Limit; + }; + // Limits results to keys that begin with the prefix + + inline void SetPrefix(std::string Prefix) + { + m_settingFlag |= SETTING_INPUT_LIST_MULTIPART_UPLOADS_PREFIX_FLAG; + m_Prefix = Prefix; + }; + + inline std::string GetPrefix() + { + return m_Prefix; + }; + // Limit results returned from the first uploading segment after upload_id_marker sorted by the time of upload_id + + inline void SetUploadIDMarker(std::string UploadIDMarker) + { + m_settingFlag |= + SETTING_INPUT_LIST_MULTIPART_UPLOADS_UPLOAD_ID_MARKER_FLAG; + m_UploadIDMarker = UploadIDMarker; + }; + + inline std::string GetUploadIDMarker() + { + return m_UploadIDMarker; + }; + +private: + + // Put all keys that share a common prefix into a list + std::string m_Delimiter; + + // Limit results returned from the first key after key_marker sorted by alphabetical order + std::string m_KeyMarker; + + // Results count limit + int m_Limit; + + // Limits results to keys that begin with the prefix + std::string m_Prefix; + + // Limit results returned from the first uploading segment after upload_id_marker sorted by the time of upload_id + std::string m_UploadIDMarker; + +}; +// ListObjectsInput presents input for ListObjects. +class QS_SDK_API ListObjectsInput:public QsInput +{ +public: + ListObjectsInput() + { + }; + + inline bool CheckIfInputIsVaild() + { + int tmpFlag = BASIC_FLAG; + return (tmpFlag == (tmpFlag & m_settingFlag)); + }; + // Put all keys that share a common prefix into a list + + inline void SetDelimiter(std::string Delimiter) + { + m_settingFlag |= SETTING_INPUT_LIST_OBJECTS_DELIMITER_FLAG; + m_Delimiter = Delimiter; + }; + + inline std::string GetDelimiter() + { + return m_Delimiter; + }; + // Results count limit + + inline void SetLimit(int Limit) + { + m_settingFlag |= SETTING_INPUT_LIST_OBJECTS_LIMIT_FLAG; + m_Limit = Limit; + }; + + inline int GetLimit() + { + return m_Limit; + }; + // Limit results to keys that start at this marker + + inline void SetMarker(std::string Marker) + { + m_settingFlag |= SETTING_INPUT_LIST_OBJECTS_MARKER_FLAG; + m_Marker = Marker; + }; + + inline std::string GetMarker() + { + return m_Marker; + }; + // Limits results to keys that begin with the prefix + + inline void SetPrefix(std::string Prefix) + { + m_settingFlag |= SETTING_INPUT_LIST_OBJECTS_PREFIX_FLAG; + m_Prefix = Prefix; + }; + + inline std::string GetPrefix() + { + return m_Prefix; + }; + +private: + + // Put all keys that share a common prefix into a list + std::string m_Delimiter; + + // Results count limit + int m_Limit; + + // Limit results to keys that start at this marker + std::string m_Marker; + + // Limits results to keys that begin with the prefix + std::string m_Prefix; + +}; +// PutBucketInput presents input for PutBucket. +typedef QsInput PutBucketInput; +// PutBucketACLInput presents input for PutBucketACL. +class QS_SDK_API PutBucketACLInput:public QsInput +{ +public: + PutBucketACLInput() + { + }; + + inline bool CheckIfInputIsVaild() + { + int tmpFlag = BASIC_FLAG | SETTING_INPUT_PUT_BUCKET_ACL_ACL_FLAG; + return (tmpFlag == (tmpFlag & m_settingFlag)); + }; + // Bucket ACL rules +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetACL(qs_list_t * acl) + { + qs_acl_item_t *item; + qs_list_for_each_entry(qs_acl_item_t, item, acl) + { + m_ACL.push_back(*item->content); + } + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetACL(std::vector < ACLType > ACL) + { + m_settingFlag |= SETTING_INPUT_PUT_BUCKET_ACL_ACL_FLAG; + m_ACL = ACL; + }; + + inline std::vector < ACLType > GetACL() + { + return m_ACL; + }; + +private: + // Bucket ACL rules + + std::vector < ACLType > m_ACL; // Required + +}; +// PutBucketCORSInput presents input for PutBucketCORS. +class QS_SDK_API PutBucketCORSInput:public QsInput +{ +public: + PutBucketCORSInput() + { + }; + + inline bool CheckIfInputIsVaild() + { + int tmpFlag = + BASIC_FLAG | SETTING_INPUT_PUT_BUCKET_CORS_CORS_RULES_FLAG; + return (tmpFlag == (tmpFlag & m_settingFlag)); + }; + // Bucket CORS rules +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetCORSRules(qs_list_t * cors_rules) + { + qs_cors_rule_item_t *item; + qs_list_for_each_entry(qs_cors_rule_item_t, item, cors_rules) + { + m_CORSRules.push_back(*item->content); + } + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetCORSRules(std::vector < CORSRuleType > CORSRules) + { + m_settingFlag |= SETTING_INPUT_PUT_BUCKET_CORS_CORS_RULES_FLAG; + m_CORSRules = CORSRules; + }; + + inline std::vector < CORSRuleType > GetCORSRules() + { + return m_CORSRules; + }; + +private: + // Bucket CORS rules + + std::vector < CORSRuleType > m_CORSRules; // Required + +}; +// PutBucketExternalMirrorInput presents input for PutBucketExternalMirror. +class QS_SDK_API PutBucketExternalMirrorInput:public QsInput +{ +public: + PutBucketExternalMirrorInput() + { + }; + + inline bool CheckIfInputIsVaild() + { + int tmpFlag = + BASIC_FLAG | + SETTING_INPUT_PUT_BUCKET_EXTERNAL_MIRROR_SOURCE_SITE_FLAG; + return (tmpFlag == (tmpFlag & m_settingFlag)); + }; + // Source site url + + inline void SetSourceSite(std::string SourceSite) + { + m_settingFlag |= + SETTING_INPUT_PUT_BUCKET_EXTERNAL_MIRROR_SOURCE_SITE_FLAG; + m_SourceSite = SourceSite; + }; + + inline std::string GetSourceSite() + { + return m_SourceSite; + }; + +private: + // Source site url + std::string m_SourceSite; // Required + +}; +// PutBucketPolicyInput presents input for PutBucketPolicy. +class QS_SDK_API PutBucketPolicyInput:public QsInput +{ +public: + PutBucketPolicyInput() + { + }; + + inline bool CheckIfInputIsVaild() + { + int tmpFlag = + BASIC_FLAG | SETTING_INPUT_PUT_BUCKET_POLICY_STATEMENT_FLAG; + return (tmpFlag == (tmpFlag & m_settingFlag)); + }; + // Bucket policy statement +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetStatement(qs_list_t * statement) + { + qs_statement_item_t *item; + qs_list_for_each_entry(qs_statement_item_t, item, statement) + { + m_Statement.push_back(*item->content); + } + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetStatement(std::vector < StatementType > Statement) + { + m_settingFlag |= SETTING_INPUT_PUT_BUCKET_POLICY_STATEMENT_FLAG; + m_Statement = Statement; + }; + + inline std::vector < StatementType > GetStatement() + { + return m_Statement; + }; + +private: + // Bucket policy statement + + std::vector < StatementType > m_Statement; // Required + +}; +// +-------------------------------------------------------------------- +// | InputClassHeader +// +-------------------------------------------------------------------- +// AbortMultipartUploadInput presents input for AbortMultipartUpload. +class QS_SDK_API AbortMultipartUploadInput:public QsInput +{ +public: + AbortMultipartUploadInput() + { + }; + + inline bool CheckIfInputIsVaild() + { + int tmpFlag = + BASIC_FLAG | + SETTING_INPUT_ABORT_MULTIPART_UPLOAD_UPLOAD_ID_FLAG; + return (tmpFlag == (tmpFlag & m_settingFlag)); + }; + // Object multipart upload ID + + inline void SetUploadID(std::string UploadID) + { + m_settingFlag |= + SETTING_INPUT_ABORT_MULTIPART_UPLOAD_UPLOAD_ID_FLAG; + m_UploadID = UploadID; + }; + + inline std::string GetUploadID() + { + return m_UploadID; + }; + +private: + + // Object multipart upload ID + std::string m_UploadID; // Required + +}; +// CompleteMultipartUploadInput presents input for CompleteMultipartUpload. +class QS_SDK_API CompleteMultipartUploadInput:public QsInput +{ +public: + CompleteMultipartUploadInput() + { + }; + + inline bool CheckIfInputIsVaild() + { + int tmpFlag = + BASIC_FLAG | + SETTING_INPUT_COMPLETE_MULTIPART_UPLOAD_UPLOAD_ID_FLAG; + return (tmpFlag == (tmpFlag & m_settingFlag)); + }; + // Object multipart upload ID + + inline void SetUploadID(std::string UploadID) + { + m_settingFlag |= + SETTING_INPUT_COMPLETE_MULTIPART_UPLOAD_UPLOAD_ID_FLAG; + m_UploadID = UploadID; + }; + + inline std::string GetUploadID() + { + return m_UploadID; + }; + + // MD5sum of the object part + + inline void SetETag(std::string ETag) + { + m_settingFlag |= SETTING_INPUT_COMPLETE_MULTIPART_UPLOAD_ETAG_FLAG; + m_ETag = ETag; + }; + + inline std::string GetETag() + { + return m_ETag; + }; + // Encryption algorithm of the object + + inline void SetXQSEncryptionCustomerAlgorithm(std:: + string + XQSEncryptionCustomerAlgorithm) + { + m_settingFlag |= + SETTING_INPUT_COMPLETE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG; + m_XQSEncryptionCustomerAlgorithm = XQSEncryptionCustomerAlgorithm; + }; + + inline std::string GetXQSEncryptionCustomerAlgorithm() + { + return m_XQSEncryptionCustomerAlgorithm; + }; + // Encryption key of the object + + inline void SetXQSEncryptionCustomerKey(std:: + string XQSEncryptionCustomerKey) + { + m_settingFlag |= + SETTING_INPUT_COMPLETE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_KEY_FLAG; + m_XQSEncryptionCustomerKey = XQSEncryptionCustomerKey; + }; + + inline std::string GetXQSEncryptionCustomerKey() + { + return m_XQSEncryptionCustomerKey; + }; + // MD5sum of encryption key + + inline void SetXQSEncryptionCustomerKeyMD5(std:: + string + XQSEncryptionCustomerKeyMD5) + { + m_settingFlag |= + SETTING_INPUT_COMPLETE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG; + m_XQSEncryptionCustomerKeyMD5 = XQSEncryptionCustomerKeyMD5; + }; + + inline std::string GetXQSEncryptionCustomerKeyMD5() + { + return m_XQSEncryptionCustomerKeyMD5; + }; + + // Object parts +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetObjectParts(qs_list_t * object_parts) + { + qs_object_part_item_t *item; + qs_list_for_each_entry(qs_object_part_item_t, item, object_parts) + { + m_ObjectParts.push_back(*item->content); + } + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetObjectParts(std::vector < ObjectPartType > ObjectParts) + { + m_settingFlag |= + SETTING_INPUT_COMPLETE_MULTIPART_UPLOAD_OBJECT_PARTS_FLAG; + m_ObjectParts = ObjectParts; + }; + + inline std::vector < ObjectPartType > GetObjectParts() + { + return m_ObjectParts; + }; + +private: + + // Object multipart upload ID + std::string m_UploadID; // Required + + // MD5sum of the object part + std::string m_ETag; + + // Encryption algorithm of the object + std::string m_XQSEncryptionCustomerAlgorithm; + + // Encryption key of the object + std::string m_XQSEncryptionCustomerKey; + + // MD5sum of encryption key + std::string m_XQSEncryptionCustomerKeyMD5; + + // Object parts + + std::vector < ObjectPartType > m_ObjectParts; + +}; +// DeleteObjectInput presents input for DeleteObject. +typedef QsInput DeleteObjectInput; +// GetObjectInput presents input for GetObject. +class QS_SDK_API GetObjectInput:public QsInput +{ +public: + GetObjectInput() + { + }; + + inline bool CheckIfInputIsVaild() + { + int tmpFlag = BASIC_FLAG; + return (tmpFlag == (tmpFlag & m_settingFlag)); + }; + // Specified the Cache-Control response header + + inline void SetResponseCacheControl(std::string ResponseCacheControl) + { + m_settingFlag |= + SETTING_INPUT_GET_OBJECT_RESPONSE_CACHE_CONTROL_FLAG; + m_ResponseCacheControl = ResponseCacheControl; + }; + + inline std::string GetResponseCacheControl() + { + return m_ResponseCacheControl; + }; + // Specified the Content-Disposition response header + + inline void SetResponseContentDisposition(std:: + string + ResponseContentDisposition) + { + m_settingFlag |= + SETTING_INPUT_GET_OBJECT_RESPONSE_CONTENT_DISPOSITION_FLAG; + m_ResponseContentDisposition = ResponseContentDisposition; + }; + + inline std::string GetResponseContentDisposition() + { + return m_ResponseContentDisposition; + }; + // Specified the Content-Encoding response header + + inline void SetResponseContentEncoding(std:: + string ResponseContentEncoding) + { + m_settingFlag |= + SETTING_INPUT_GET_OBJECT_RESPONSE_CONTENT_ENCODING_FLAG; + m_ResponseContentEncoding = ResponseContentEncoding; + }; + + inline std::string GetResponseContentEncoding() + { + return m_ResponseContentEncoding; + }; + // Specified the Content-Language response header + + inline void SetResponseContentLanguage(std:: + string ResponseContentLanguage) + { + m_settingFlag |= + SETTING_INPUT_GET_OBJECT_RESPONSE_CONTENT_LANGUAGE_FLAG; + m_ResponseContentLanguage = ResponseContentLanguage; + }; + + inline std::string GetResponseContentLanguage() + { + return m_ResponseContentLanguage; + }; + // Specified the Content-Type response header + + inline void SetResponseContentType(std::string ResponseContentType) + { + m_settingFlag |= + SETTING_INPUT_GET_OBJECT_RESPONSE_CONTENT_TYPE_FLAG; + m_ResponseContentType = ResponseContentType; + }; + + inline std::string GetResponseContentType() + { + return m_ResponseContentType; + }; + // Specified the Expires response header + + inline void SetResponseExpires(std::string ResponseExpires) + { + m_settingFlag |= SETTING_INPUT_GET_OBJECT_RESPONSE_EXPIRES_FLAG; + m_ResponseExpires = ResponseExpires; + }; + + inline std::string GetResponseExpires() + { + return m_ResponseExpires; + }; + + // Check whether the ETag matches + + inline void SetIfMatch(std::string IfMatch) + { + m_settingFlag |= SETTING_INPUT_GET_OBJECT_IF_MATCH_FLAG; + m_IfMatch = IfMatch; + }; + + inline std::string GetIfMatch() + { + return m_IfMatch; + }; + // Check whether the object has been modified +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetIfModifiedSince(char *if_modified_since) + { + m_IfModifiedSince = if_modified_since; + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetIfModifiedSince(std::string IfModifiedSince) + { + m_settingFlag |= SETTING_INPUT_GET_OBJECT_IF_MODIFIED_SINCE_FLAG; + m_IfModifiedSince = IfModifiedSince; + }; + + inline std::string GetIfModifiedSince() + { + return m_IfModifiedSince; + }; + // Check whether the ETag does not match + + inline void SetIfNoneMatch(std::string IfNoneMatch) + { + m_settingFlag |= SETTING_INPUT_GET_OBJECT_IF_NONE_MATCH_FLAG; + m_IfNoneMatch = IfNoneMatch; + }; + + inline std::string GetIfNoneMatch() + { + return m_IfNoneMatch; + }; + // Check whether the object has not been modified +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetIfUnmodifiedSince(char *if_unmodified_since) + { + m_IfUnmodifiedSince = if_unmodified_since; + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetIfUnmodifiedSince(std::string IfUnmodifiedSince) + { + m_settingFlag |= SETTING_INPUT_GET_OBJECT_IF_UNMODIFIED_SINCE_FLAG; + m_IfUnmodifiedSince = IfUnmodifiedSince; + }; + + inline std::string GetIfUnmodifiedSince() + { + return m_IfUnmodifiedSince; + }; + // Specified range of the object + + inline void SetRange(std::string Range) + { + m_settingFlag |= SETTING_INPUT_GET_OBJECT_RANGE_FLAG; + m_Range = Range; + }; + + inline std::string GetRange() + { + return m_Range; + }; + // Encryption algorithm of the object + + inline void SetXQSEncryptionCustomerAlgorithm(std:: + string + XQSEncryptionCustomerAlgorithm) + { + m_settingFlag |= + SETTING_INPUT_GET_OBJECT_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG; + m_XQSEncryptionCustomerAlgorithm = XQSEncryptionCustomerAlgorithm; + }; + + inline std::string GetXQSEncryptionCustomerAlgorithm() + { + return m_XQSEncryptionCustomerAlgorithm; + }; + // Encryption key of the object + + inline void SetXQSEncryptionCustomerKey(std:: + string XQSEncryptionCustomerKey) + { + m_settingFlag |= + SETTING_INPUT_GET_OBJECT_X_QS_ENCRYPTION_CUSTOMER_KEY_FLAG; + m_XQSEncryptionCustomerKey = XQSEncryptionCustomerKey; + }; + + inline std::string GetXQSEncryptionCustomerKey() + { + return m_XQSEncryptionCustomerKey; + }; + // MD5sum of encryption key + + inline void SetXQSEncryptionCustomerKeyMD5(std:: + string + XQSEncryptionCustomerKeyMD5) + { + m_settingFlag |= + SETTING_INPUT_GET_OBJECT_X_QS_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG; + m_XQSEncryptionCustomerKeyMD5 = XQSEncryptionCustomerKeyMD5; + }; + + inline std::string GetXQSEncryptionCustomerKeyMD5() + { + return m_XQSEncryptionCustomerKeyMD5; + }; + +private: + + // Specified the Cache-Control response header + std::string m_ResponseCacheControl; + + // Specified the Content-Disposition response header + std::string m_ResponseContentDisposition; + + // Specified the Content-Encoding response header + std::string m_ResponseContentEncoding; + + // Specified the Content-Language response header + std::string m_ResponseContentLanguage; + + // Specified the Content-Type response header + std::string m_ResponseContentType; + + // Specified the Expires response header + std::string m_ResponseExpires; + + // Check whether the ETag matches + std::string m_IfMatch; + + // Check whether the object has been modified + std::string m_IfModifiedSince; + + // Check whether the ETag does not match + std::string m_IfNoneMatch; + + // Check whether the object has not been modified + std::string m_IfUnmodifiedSince; + + // Specified range of the object + std::string m_Range; + + // Encryption algorithm of the object + std::string m_XQSEncryptionCustomerAlgorithm; + + // Encryption key of the object + std::string m_XQSEncryptionCustomerKey; + + // MD5sum of encryption key + std::string m_XQSEncryptionCustomerKeyMD5; + +}; +// HeadObjectInput presents input for HeadObject. +class QS_SDK_API HeadObjectInput:public QsInput +{ +public: + HeadObjectInput() + { + }; + + inline bool CheckIfInputIsVaild() + { + int tmpFlag = BASIC_FLAG; + return (tmpFlag == (tmpFlag & m_settingFlag)); + }; + // Check whether the ETag matches + + inline void SetIfMatch(std::string IfMatch) + { + m_settingFlag |= SETTING_INPUT_HEAD_OBJECT_IF_MATCH_FLAG; + m_IfMatch = IfMatch; + }; + + inline std::string GetIfMatch() + { + return m_IfMatch; + }; + // Check whether the object has been modified +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetIfModifiedSince(char *if_modified_since) + { + m_IfModifiedSince = if_modified_since; + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetIfModifiedSince(std::string IfModifiedSince) + { + m_settingFlag |= SETTING_INPUT_HEAD_OBJECT_IF_MODIFIED_SINCE_FLAG; + m_IfModifiedSince = IfModifiedSince; + }; + + inline std::string GetIfModifiedSince() + { + return m_IfModifiedSince; + }; + // Check whether the ETag does not match + + inline void SetIfNoneMatch(std::string IfNoneMatch) + { + m_settingFlag |= SETTING_INPUT_HEAD_OBJECT_IF_NONE_MATCH_FLAG; + m_IfNoneMatch = IfNoneMatch; + }; + + inline std::string GetIfNoneMatch() + { + return m_IfNoneMatch; + }; + // Check whether the object has not been modified +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetIfUnmodifiedSince(char *if_unmodified_since) + { + m_IfUnmodifiedSince = if_unmodified_since; + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetIfUnmodifiedSince(std::string IfUnmodifiedSince) + { + m_settingFlag |= SETTING_INPUT_HEAD_OBJECT_IF_UNMODIFIED_SINCE_FLAG; + m_IfUnmodifiedSince = IfUnmodifiedSince; + }; + + inline std::string GetIfUnmodifiedSince() + { + return m_IfUnmodifiedSince; + }; + // Encryption algorithm of the object + + inline void SetXQSEncryptionCustomerAlgorithm(std:: + string + XQSEncryptionCustomerAlgorithm) + { + m_settingFlag |= + SETTING_INPUT_HEAD_OBJECT_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG; + m_XQSEncryptionCustomerAlgorithm = XQSEncryptionCustomerAlgorithm; + }; + + inline std::string GetXQSEncryptionCustomerAlgorithm() + { + return m_XQSEncryptionCustomerAlgorithm; + }; + // Encryption key of the object + + inline void SetXQSEncryptionCustomerKey(std:: + string XQSEncryptionCustomerKey) + { + m_settingFlag |= + SETTING_INPUT_HEAD_OBJECT_X_QS_ENCRYPTION_CUSTOMER_KEY_FLAG; + m_XQSEncryptionCustomerKey = XQSEncryptionCustomerKey; + }; + + inline std::string GetXQSEncryptionCustomerKey() + { + return m_XQSEncryptionCustomerKey; + }; + // MD5sum of encryption key + + inline void SetXQSEncryptionCustomerKeyMD5(std:: + string + XQSEncryptionCustomerKeyMD5) + { + m_settingFlag |= + SETTING_INPUT_HEAD_OBJECT_X_QS_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG; + m_XQSEncryptionCustomerKeyMD5 = XQSEncryptionCustomerKeyMD5; + }; + + inline std::string GetXQSEncryptionCustomerKeyMD5() + { + return m_XQSEncryptionCustomerKeyMD5; + }; + +private: + // Check whether the ETag matches + std::string m_IfMatch; + + // Check whether the object has been modified + std::string m_IfModifiedSince; + + // Check whether the ETag does not match + std::string m_IfNoneMatch; + + // Check whether the object has not been modified + std::string m_IfUnmodifiedSince; + + // Encryption algorithm of the object + std::string m_XQSEncryptionCustomerAlgorithm; + + // Encryption key of the object + std::string m_XQSEncryptionCustomerKey; + + // MD5sum of encryption key + std::string m_XQSEncryptionCustomerKeyMD5; + +}; +// ImageProcessInput presents input for ImageProcess. +class QS_SDK_API ImageProcessInput:public QsInput +{ +public: + ImageProcessInput() + { + }; + + inline bool CheckIfInputIsVaild() + { + int tmpFlag = BASIC_FLAG | SETTING_INPUT_IMAGE_PROCESS_ACTION_FLAG; + return (tmpFlag == (tmpFlag & m_settingFlag)); + }; + // Image process action + + inline void SetAction(std::string Action) + { + m_settingFlag |= SETTING_INPUT_IMAGE_PROCESS_ACTION_FLAG; + m_Action = Action; + }; + + inline std::string GetAction() + { + return m_Action; + }; + // Specified the Cache-Control response header + + inline void SetResponseCacheControl(std::string ResponseCacheControl) + { + m_settingFlag |= + SETTING_INPUT_IMAGE_PROCESS_RESPONSE_CACHE_CONTROL_FLAG; + m_ResponseCacheControl = ResponseCacheControl; + }; + + inline std::string GetResponseCacheControl() + { + return m_ResponseCacheControl; + }; + // Specified the Content-Disposition response header + + inline void SetResponseContentDisposition(std:: + string + ResponseContentDisposition) + { + m_settingFlag |= + SETTING_INPUT_IMAGE_PROCESS_RESPONSE_CONTENT_DISPOSITION_FLAG; + m_ResponseContentDisposition = ResponseContentDisposition; + }; + + inline std::string GetResponseContentDisposition() + { + return m_ResponseContentDisposition; + }; + // Specified the Content-Encoding response header + + inline void SetResponseContentEncoding(std:: + string ResponseContentEncoding) + { + m_settingFlag |= + SETTING_INPUT_IMAGE_PROCESS_RESPONSE_CONTENT_ENCODING_FLAG; + m_ResponseContentEncoding = ResponseContentEncoding; + }; + + inline std::string GetResponseContentEncoding() + { + return m_ResponseContentEncoding; + }; + // Specified the Content-Language response header + + inline void SetResponseContentLanguage(std:: + string ResponseContentLanguage) + { + m_settingFlag |= + SETTING_INPUT_IMAGE_PROCESS_RESPONSE_CONTENT_LANGUAGE_FLAG; + m_ResponseContentLanguage = ResponseContentLanguage; + }; + + inline std::string GetResponseContentLanguage() + { + return m_ResponseContentLanguage; + }; + // Specified the Content-Type response header + + inline void SetResponseContentType(std::string ResponseContentType) + { + m_settingFlag |= + SETTING_INPUT_IMAGE_PROCESS_RESPONSE_CONTENT_TYPE_FLAG; + m_ResponseContentType = ResponseContentType; + }; + + inline std::string GetResponseContentType() + { + return m_ResponseContentType; + }; + // Specified the Expires response header + + inline void SetResponseExpires(std::string ResponseExpires) + { + m_settingFlag |= SETTING_INPUT_IMAGE_PROCESS_RESPONSE_EXPIRES_FLAG; + m_ResponseExpires = ResponseExpires; + }; + + inline std::string GetResponseExpires() + { + return m_ResponseExpires; + }; + + // Check whether the object has been modified +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetIfModifiedSince(char *if_modified_since) + { + m_IfModifiedSince = if_modified_since; + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetIfModifiedSince(std::string IfModifiedSince) + { + m_settingFlag |= SETTING_INPUT_IMAGE_PROCESS_IF_MODIFIED_SINCE_FLAG; + m_IfModifiedSince = IfModifiedSince; + }; + + inline std::string GetIfModifiedSince() + { + return m_IfModifiedSince; + }; + +private: + + // Image process action + std::string m_Action; // Required + + // Specified the Cache-Control response header + std::string m_ResponseCacheControl; + + // Specified the Content-Disposition response header + std::string m_ResponseContentDisposition; + + // Specified the Content-Encoding response header + std::string m_ResponseContentEncoding; + + // Specified the Content-Language response header + std::string m_ResponseContentLanguage; + + // Specified the Content-Type response header + std::string m_ResponseContentType; + + // Specified the Expires response header + std::string m_ResponseExpires; + + // Check whether the object has been modified + std::string m_IfModifiedSince; + +}; +// InitiateMultipartUploadInput presents input for InitiateMultipartUpload. +class QS_SDK_API InitiateMultipartUploadInput:public QsInput +{ +public: + InitiateMultipartUploadInput() + { + }; + + inline bool CheckIfInputIsVaild() + { + int tmpFlag = BASIC_FLAG; + return (tmpFlag == (tmpFlag & m_settingFlag)); + }; + // Object content type + + inline void SetContentType(std::string ContentType) + { + m_settingFlag |= + SETTING_INPUT_INITIATE_MULTIPART_UPLOAD_CONTENT_TYPE_FLAG; + m_ContentType = ContentType; + }; + + inline std::string GetContentType() + { + return m_ContentType; + }; + // Encryption algorithm of the object + + inline void SetXQSEncryptionCustomerAlgorithm(std:: + string + XQSEncryptionCustomerAlgorithm) + { + m_settingFlag |= + SETTING_INPUT_INITIATE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG; + m_XQSEncryptionCustomerAlgorithm = XQSEncryptionCustomerAlgorithm; + }; + + inline std::string GetXQSEncryptionCustomerAlgorithm() + { + return m_XQSEncryptionCustomerAlgorithm; + }; + // Encryption key of the object + + inline void SetXQSEncryptionCustomerKey(std:: + string XQSEncryptionCustomerKey) + { + m_settingFlag |= + SETTING_INPUT_INITIATE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_KEY_FLAG; + m_XQSEncryptionCustomerKey = XQSEncryptionCustomerKey; + }; + + inline std::string GetXQSEncryptionCustomerKey() + { + return m_XQSEncryptionCustomerKey; + }; + // MD5sum of encryption key + + inline void SetXQSEncryptionCustomerKeyMD5(std:: + string + XQSEncryptionCustomerKeyMD5) + { + m_settingFlag |= + SETTING_INPUT_INITIATE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG; + m_XQSEncryptionCustomerKeyMD5 = XQSEncryptionCustomerKeyMD5; + }; + + inline std::string GetXQSEncryptionCustomerKeyMD5() + { + return m_XQSEncryptionCustomerKeyMD5; + }; + +private: + // Object content type + std::string m_ContentType; + + // Encryption algorithm of the object + std::string m_XQSEncryptionCustomerAlgorithm; + + // Encryption key of the object + std::string m_XQSEncryptionCustomerKey; + + // MD5sum of encryption key + std::string m_XQSEncryptionCustomerKeyMD5; + +}; +// ListMultipartInput presents input for ListMultipart. +class QS_SDK_API ListMultipartInput:public QsInput +{ +public: + ListMultipartInput() + { + }; + + inline bool CheckIfInputIsVaild() + { + int tmpFlag = + BASIC_FLAG | SETTING_INPUT_LIST_MULTIPART_UPLOAD_ID_FLAG; + return (tmpFlag == (tmpFlag & m_settingFlag)); + }; + // Limit results count + + inline void SetLimit(int Limit) + { + m_settingFlag |= SETTING_INPUT_LIST_MULTIPART_LIMIT_FLAG; + m_Limit = Limit; + }; + + inline int GetLimit() + { + return m_Limit; + }; + // Object multipart upload part number + + inline void SetPartNumberMarker(int PartNumberMarker) + { + m_settingFlag |= + SETTING_INPUT_LIST_MULTIPART_PART_NUMBER_MARKER_FLAG; + m_PartNumberMarker = PartNumberMarker; + }; + + inline int GetPartNumberMarker() + { + return m_PartNumberMarker; + }; + // Object multipart upload ID + + inline void SetUploadID(std::string UploadID) + { + m_settingFlag |= SETTING_INPUT_LIST_MULTIPART_UPLOAD_ID_FLAG; + m_UploadID = UploadID; + }; + + inline std::string GetUploadID() + { + return m_UploadID; + }; + +private: + + // Limit results count + int m_Limit; + + // Object multipart upload part number + int m_PartNumberMarker; + + // Object multipart upload ID + std::string m_UploadID; // Required + +}; +// OptionsObjectInput presents input for OptionsObject. +class QS_SDK_API OptionsObjectInput:public QsInput +{ +public: + OptionsObjectInput() + { + }; + + inline bool CheckIfInputIsVaild() + { + int tmpFlag = + BASIC_FLAG | + SETTING_INPUT_OPTIONS_OBJECT_ACCESS_CONTROL_REQUEST_METHOD_FLAG + | SETTING_INPUT_OPTIONS_OBJECT_ORIGIN_FLAG; + return (tmpFlag == (tmpFlag & m_settingFlag)); + }; + // Request headers + + inline void SetAccessControlRequestHeaders(std:: + string + AccessControlRequestHeaders) + { + m_settingFlag |= + SETTING_INPUT_OPTIONS_OBJECT_ACCESS_CONTROL_REQUEST_HEADERS_FLAG; + m_AccessControlRequestHeaders = AccessControlRequestHeaders; + }; + + inline std::string GetAccessControlRequestHeaders() + { + return m_AccessControlRequestHeaders; + }; + // Request method + + inline void SetAccessControlRequestMethod(std:: + string + AccessControlRequestMethod) + { + m_settingFlag |= + SETTING_INPUT_OPTIONS_OBJECT_ACCESS_CONTROL_REQUEST_METHOD_FLAG; + m_AccessControlRequestMethod = AccessControlRequestMethod; + }; + + inline std::string GetAccessControlRequestMethod() + { + return m_AccessControlRequestMethod; + }; + // Request origin + + inline void SetOrigin(std::string Origin) + { + m_settingFlag |= SETTING_INPUT_OPTIONS_OBJECT_ORIGIN_FLAG; + m_Origin = Origin; + }; + + inline std::string GetOrigin() + { + return m_Origin; + }; + +private: + // Request headers + std::string m_AccessControlRequestHeaders; + + // Request method + std::string m_AccessControlRequestMethod; // Required + + // Request origin + std::string m_Origin; // Required + +}; +// PutObjectInput presents input for PutObject. +class QS_SDK_API PutObjectInput:public QsInput +{ +public: + PutObjectInput():m_streambody(NULL) + { + }; + + inline bool CheckIfInputIsVaild() + { + int tmpFlag = + BASIC_FLAG | SETTING_INPUT_PUT_OBJECT_CONTENT_LENGTH_FLAG; + return (tmpFlag == (tmpFlag & m_settingFlag)); + }; + // Object content size + + inline void SetContentLength(int64_t ContentLength) + { + m_settingFlag |= SETTING_INPUT_PUT_OBJECT_CONTENT_LENGTH_FLAG; + m_ContentLength = ContentLength; + }; + + inline int64_t GetContentLength() + { + return m_ContentLength; + }; + // Object MD5sum + + inline void SetContentMD5(std::string ContentMD5) + { + m_settingFlag |= SETTING_INPUT_PUT_OBJECT_CONTENT_MD5_FLAG; + m_ContentMD5 = ContentMD5; + }; + + inline std::string GetContentMD5() + { + return m_ContentMD5; + }; + // Object content type + + inline void SetContentType(std::string ContentType) + { + m_settingFlag |= SETTING_INPUT_PUT_OBJECT_CONTENT_TYPE_FLAG; + m_ContentType = ContentType; + }; + + inline std::string GetContentType() + { + return m_ContentType; + }; + // Used to indicate that particular server behaviors are required by the client + + inline void SetExpect(std::string Expect) + { + m_settingFlag |= SETTING_INPUT_PUT_OBJECT_EXPECT_FLAG; + m_Expect = Expect; + }; + + inline std::string GetExpect() + { + return m_Expect; + }; + // Copy source, format (//) + + inline void SetXQSCopySource(std::string XQSCopySource) + { + m_settingFlag |= SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_FLAG; + m_XQSCopySource = XQSCopySource; + }; + + inline std::string GetXQSCopySource() + { + return m_XQSCopySource; + }; + // Encryption algorithm of the object + + inline void SetXQSCopySourceEncryptionCustomerAlgorithm(std:: + string + XQSCopySourceEncryptionCustomerAlgorithm) + { + m_settingFlag |= + SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG; + m_XQSCopySourceEncryptionCustomerAlgorithm = + XQSCopySourceEncryptionCustomerAlgorithm; + }; + + inline std::string GetXQSCopySourceEncryptionCustomerAlgorithm() + { + return m_XQSCopySourceEncryptionCustomerAlgorithm; + }; + // Encryption key of the object + + inline void SetXQSCopySourceEncryptionCustomerKey(std:: + string + XQSCopySourceEncryptionCustomerKey) + { + m_settingFlag |= + SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_ENCRYPTION_CUSTOMER_KEY_FLAG; + m_XQSCopySourceEncryptionCustomerKey = + XQSCopySourceEncryptionCustomerKey; + }; + + inline std::string GetXQSCopySourceEncryptionCustomerKey() + { + return m_XQSCopySourceEncryptionCustomerKey; + }; + // MD5sum of encryption key + + inline void SetXQSCopySourceEncryptionCustomerKeyMD5(std:: + string + XQSCopySourceEncryptionCustomerKeyMD5) + { + m_settingFlag |= + SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG; + m_XQSCopySourceEncryptionCustomerKeyMD5 = + XQSCopySourceEncryptionCustomerKeyMD5; + }; + + inline std::string GetXQSCopySourceEncryptionCustomerKeyMD5() + { + return m_XQSCopySourceEncryptionCustomerKeyMD5; + }; + // Check whether the copy source matches + + inline void SetXQSCopySourceIfMatch(std::string XQSCopySourceIfMatch) + { + m_settingFlag |= + SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_IF_MATCH_FLAG; + m_XQSCopySourceIfMatch = XQSCopySourceIfMatch; + }; + + inline std::string GetXQSCopySourceIfMatch() + { + return m_XQSCopySourceIfMatch; + }; + // Check whether the copy source has been modified +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetXQSCopySourceIfModifiedSince(char + *x_qs_copy_source_if_modified_since) + { + m_XQSCopySourceIfModifiedSince = x_qs_copy_source_if_modified_since; + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetXQSCopySourceIfModifiedSince(std:: + string + XQSCopySourceIfModifiedSince) + { + m_settingFlag |= + SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_IF_MODIFIED_SINCE_FLAG; + m_XQSCopySourceIfModifiedSince = XQSCopySourceIfModifiedSince; + }; + + inline std::string GetXQSCopySourceIfModifiedSince() + { + return m_XQSCopySourceIfModifiedSince; + }; + // Check whether the copy source does not match + + inline void SetXQSCopySourceIfNoneMatch(std:: + string XQSCopySourceIfNoneMatch) + { + m_settingFlag |= + SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_IF_NONE_MATCH_FLAG; + m_XQSCopySourceIfNoneMatch = XQSCopySourceIfNoneMatch; + }; + + inline std::string GetXQSCopySourceIfNoneMatch() + { + return m_XQSCopySourceIfNoneMatch; + }; + // Check whether the copy source has not been modified +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetXQSCopySourceIfUnmodifiedSince(char + *x_qs_copy_source_if_unmodified_since) + { + m_XQSCopySourceIfUnmodifiedSince = + x_qs_copy_source_if_unmodified_since; + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetXQSCopySourceIfUnmodifiedSince(std:: + string + XQSCopySourceIfUnmodifiedSince) + { + m_settingFlag |= + SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_IF_UNMODIFIED_SINCE_FLAG; + m_XQSCopySourceIfUnmodifiedSince = XQSCopySourceIfUnmodifiedSince; + }; + + inline std::string GetXQSCopySourceIfUnmodifiedSince() + { + return m_XQSCopySourceIfUnmodifiedSince; + }; + // Encryption algorithm of the object + + inline void SetXQSEncryptionCustomerAlgorithm(std:: + string + XQSEncryptionCustomerAlgorithm) + { + m_settingFlag |= + SETTING_INPUT_PUT_OBJECT_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG; + m_XQSEncryptionCustomerAlgorithm = XQSEncryptionCustomerAlgorithm; + }; + + inline std::string GetXQSEncryptionCustomerAlgorithm() + { + return m_XQSEncryptionCustomerAlgorithm; + }; + // Encryption key of the object + + inline void SetXQSEncryptionCustomerKey(std:: + string XQSEncryptionCustomerKey) + { + m_settingFlag |= + SETTING_INPUT_PUT_OBJECT_X_QS_ENCRYPTION_CUSTOMER_KEY_FLAG; + m_XQSEncryptionCustomerKey = XQSEncryptionCustomerKey; + }; + + inline std::string GetXQSEncryptionCustomerKey() + { + return m_XQSEncryptionCustomerKey; + }; + // MD5sum of encryption key + + inline void SetXQSEncryptionCustomerKeyMD5(std:: + string + XQSEncryptionCustomerKeyMD5) + { + m_settingFlag |= + SETTING_INPUT_PUT_OBJECT_X_QS_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG; + m_XQSEncryptionCustomerKeyMD5 = XQSEncryptionCustomerKeyMD5; + }; + + inline std::string GetXQSEncryptionCustomerKeyMD5() + { + return m_XQSEncryptionCustomerKeyMD5; + }; + // Check whether fetch target object has not been modified +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetXQSFetchIfUnmodifiedSince(char + *x_qs_fetch_if_unmodified_since) + { + m_XQSFetchIfUnmodifiedSince = x_qs_fetch_if_unmodified_since; + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetXQSFetchIfUnmodifiedSince(std:: + string + XQSFetchIfUnmodifiedSince) + { + m_settingFlag |= + SETTING_INPUT_PUT_OBJECT_X_QS_FETCH_IF_UNMODIFIED_SINCE_FLAG; + m_XQSFetchIfUnmodifiedSince = XQSFetchIfUnmodifiedSince; + }; + + inline std::string GetXQSFetchIfUnmodifiedSince() + { + return m_XQSFetchIfUnmodifiedSince; + }; + // Fetch source, should be a valid url + + inline void SetXQSFetchSource(std::string XQSFetchSource) + { + m_settingFlag |= SETTING_INPUT_PUT_OBJECT_X_QS_FETCH_SOURCE_FLAG; + m_XQSFetchSource = XQSFetchSource; + }; + + inline std::string GetXQSFetchSource() + { + return m_XQSFetchSource; + }; + // Move source, format (//) + + inline void SetXQSMoveSource(std::string XQSMoveSource) + { + m_settingFlag |= SETTING_INPUT_PUT_OBJECT_X_QS_MOVE_SOURCE_FLAG; + m_XQSMoveSource = XQSMoveSource; + }; + + inline std::string GetXQSMoveSource() + { + return m_XQSMoveSource; + }; + + std::iostream * GetBody() + { + return m_streambody; + }; + void SetBody(std::iostream * streambody) + { + m_streambody = streambody; + }; +private: + // Object content size + int64_t m_ContentLength; // Required + + // Object MD5sum + std::string m_ContentMD5; + + // Object content type + std::string m_ContentType; + + // Used to indicate that particular server behaviors are required by the client + std::string m_Expect; + + // Copy source, format (//) + std::string m_XQSCopySource; + + // Encryption algorithm of the object + std::string m_XQSCopySourceEncryptionCustomerAlgorithm; + + // Encryption key of the object + std::string m_XQSCopySourceEncryptionCustomerKey; + + // MD5sum of encryption key + std::string m_XQSCopySourceEncryptionCustomerKeyMD5; + + // Check whether the copy source matches + std::string m_XQSCopySourceIfMatch; + + // Check whether the copy source has been modified + std::string m_XQSCopySourceIfModifiedSince; + + // Check whether the copy source does not match + std::string m_XQSCopySourceIfNoneMatch; + + // Check whether the copy source has not been modified + std::string m_XQSCopySourceIfUnmodifiedSince; + + // Encryption algorithm of the object + std::string m_XQSEncryptionCustomerAlgorithm; + + // Encryption key of the object + std::string m_XQSEncryptionCustomerKey; + + // MD5sum of encryption key + std::string m_XQSEncryptionCustomerKeyMD5; + + // Check whether fetch target object has not been modified + std::string m_XQSFetchIfUnmodifiedSince; + + // Fetch source, should be a valid url + std::string m_XQSFetchSource; + + // Move source, format (//) + std::string m_XQSMoveSource; + + std::iostream * m_streambody; +}; +// UploadMultipartInput presents input for UploadMultipart. +class QS_SDK_API UploadMultipartInput:public QsInput +{ +public: + UploadMultipartInput():m_streambody(NULL) + { + }; + + inline bool CheckIfInputIsVaild() + { + int tmpFlag = + BASIC_FLAG | SETTING_INPUT_UPLOAD_MULTIPART_PART_NUMBER_FLAG | + SETTING_INPUT_UPLOAD_MULTIPART_UPLOAD_ID_FLAG; + return (tmpFlag == (tmpFlag & m_settingFlag)); + }; + // Object multipart upload part number + + inline void SetPartNumber(int PartNumber) + { + m_settingFlag |= SETTING_INPUT_UPLOAD_MULTIPART_PART_NUMBER_FLAG; + m_PartNumber = PartNumber; + }; + + inline int GetPartNumber() + { + return m_PartNumber; + }; + // Object multipart upload ID + + inline void SetUploadID(std::string UploadID) + { + m_settingFlag |= SETTING_INPUT_UPLOAD_MULTIPART_UPLOAD_ID_FLAG; + m_UploadID = UploadID; + }; + + inline std::string GetUploadID() + { + return m_UploadID; + }; + + // Object multipart content length + + inline void SetContentLength(int64_t ContentLength) + { + m_settingFlag |= SETTING_INPUT_UPLOAD_MULTIPART_CONTENT_LENGTH_FLAG; + m_ContentLength = ContentLength; + }; + + inline int64_t GetContentLength() + { + return m_ContentLength; + }; + // Object multipart content MD5sum + + inline void SetContentMD5(std::string ContentMD5) + { + m_settingFlag |= SETTING_INPUT_UPLOAD_MULTIPART_CONTENT_MD5_FLAG; + m_ContentMD5 = ContentMD5; + }; + + inline std::string GetContentMD5() + { + return m_ContentMD5; + }; + // Specify range of the source object + + inline void SetXQSCopyRange(std::string XQSCopyRange) + { + m_settingFlag |= + SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_RANGE_FLAG; + m_XQSCopyRange = XQSCopyRange; + }; + + inline std::string GetXQSCopyRange() + { + return m_XQSCopyRange; + }; + // Copy source, format (//) + + inline void SetXQSCopySource(std::string XQSCopySource) + { + m_settingFlag |= + SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_FLAG; + m_XQSCopySource = XQSCopySource; + }; + + inline std::string GetXQSCopySource() + { + return m_XQSCopySource; + }; + // Encryption algorithm of the object + + inline void SetXQSCopySourceEncryptionCustomerAlgorithm(std:: + string + XQSCopySourceEncryptionCustomerAlgorithm) + { + m_settingFlag |= + SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG; + m_XQSCopySourceEncryptionCustomerAlgorithm = + XQSCopySourceEncryptionCustomerAlgorithm; + }; + + inline std::string GetXQSCopySourceEncryptionCustomerAlgorithm() + { + return m_XQSCopySourceEncryptionCustomerAlgorithm; + }; + // Encryption key of the object + + inline void SetXQSCopySourceEncryptionCustomerKey(std:: + string + XQSCopySourceEncryptionCustomerKey) + { + m_settingFlag |= + SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_ENCRYPTION_CUSTOMER_KEY_FLAG; + m_XQSCopySourceEncryptionCustomerKey = + XQSCopySourceEncryptionCustomerKey; + }; + + inline std::string GetXQSCopySourceEncryptionCustomerKey() + { + return m_XQSCopySourceEncryptionCustomerKey; + }; + // MD5sum of encryption key + + inline void SetXQSCopySourceEncryptionCustomerKeyMD5(std:: + string + XQSCopySourceEncryptionCustomerKeyMD5) + { + m_settingFlag |= + SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG; + m_XQSCopySourceEncryptionCustomerKeyMD5 = + XQSCopySourceEncryptionCustomerKeyMD5; + }; + + inline std::string GetXQSCopySourceEncryptionCustomerKeyMD5() + { + return m_XQSCopySourceEncryptionCustomerKeyMD5; + }; + // Check whether the Etag of copy source matches the specified value + + inline void SetXQSCopySourceIfMatch(std::string XQSCopySourceIfMatch) + { + m_settingFlag |= + SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_IF_MATCH_FLAG; + m_XQSCopySourceIfMatch = XQSCopySourceIfMatch; + }; + + inline std::string GetXQSCopySourceIfMatch() + { + return m_XQSCopySourceIfMatch; + }; + // Check whether the copy source has been modified since the specified date +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetXQSCopySourceIfModifiedSince(char + *x_qs_copy_source_if_modified_since) + { + m_XQSCopySourceIfModifiedSince = x_qs_copy_source_if_modified_since; + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetXQSCopySourceIfModifiedSince(std:: + string + XQSCopySourceIfModifiedSince) + { + m_settingFlag |= + SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_IF_MODIFIED_SINCE_FLAG; + m_XQSCopySourceIfModifiedSince = XQSCopySourceIfModifiedSince; + }; + + inline std::string GetXQSCopySourceIfModifiedSince() + { + return m_XQSCopySourceIfModifiedSince; + }; + // Check whether the Etag of copy source does not matches the specified value + + inline void SetXQSCopySourceIfNoneMatch(std:: + string XQSCopySourceIfNoneMatch) + { + m_settingFlag |= + SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_IF_NONE_MATCH_FLAG; + m_XQSCopySourceIfNoneMatch = XQSCopySourceIfNoneMatch; + }; + + inline std::string GetXQSCopySourceIfNoneMatch() + { + return m_XQSCopySourceIfNoneMatch; + }; + // Check whether the copy source has not been unmodified since the specified date +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetXQSCopySourceIfUnmodifiedSince(char + *x_qs_copy_source_if_unmodified_since) + { + m_XQSCopySourceIfUnmodifiedSince = + x_qs_copy_source_if_unmodified_since; + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetXQSCopySourceIfUnmodifiedSince(std:: + string + XQSCopySourceIfUnmodifiedSince) + { + m_settingFlag |= + SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_IF_UNMODIFIED_SINCE_FLAG; + m_XQSCopySourceIfUnmodifiedSince = XQSCopySourceIfUnmodifiedSince; + }; + + inline std::string GetXQSCopySourceIfUnmodifiedSince() + { + return m_XQSCopySourceIfUnmodifiedSince; + }; + // Encryption algorithm of the object + + inline void SetXQSEncryptionCustomerAlgorithm(std:: + string + XQSEncryptionCustomerAlgorithm) + { + m_settingFlag |= + SETTING_INPUT_UPLOAD_MULTIPART_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG; + m_XQSEncryptionCustomerAlgorithm = XQSEncryptionCustomerAlgorithm; + }; + + inline std::string GetXQSEncryptionCustomerAlgorithm() + { + return m_XQSEncryptionCustomerAlgorithm; + }; + // Encryption key of the object + + inline void SetXQSEncryptionCustomerKey(std:: + string XQSEncryptionCustomerKey) + { + m_settingFlag |= + SETTING_INPUT_UPLOAD_MULTIPART_X_QS_ENCRYPTION_CUSTOMER_KEY_FLAG; + m_XQSEncryptionCustomerKey = XQSEncryptionCustomerKey; + }; + + inline std::string GetXQSEncryptionCustomerKey() + { + return m_XQSEncryptionCustomerKey; + }; + // MD5sum of encryption key + + inline void SetXQSEncryptionCustomerKeyMD5(std:: + string + XQSEncryptionCustomerKeyMD5) + { + m_settingFlag |= + SETTING_INPUT_UPLOAD_MULTIPART_X_QS_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG; + m_XQSEncryptionCustomerKeyMD5 = XQSEncryptionCustomerKeyMD5; + }; + + inline std::string GetXQSEncryptionCustomerKeyMD5() + { + return m_XQSEncryptionCustomerKeyMD5; + }; + + std::iostream * GetBody() + { + return m_streambody; + }; + void SetBody(std::iostream * streambody) + { + m_streambody = streambody; + }; +private: + + // Object multipart upload part number + int m_PartNumber; // Required + + // Object multipart upload ID + std::string m_UploadID; // Required + + // Object multipart content length + int64_t m_ContentLength; + + // Object multipart content MD5sum + std::string m_ContentMD5; + + // Specify range of the source object + std::string m_XQSCopyRange; + + // Copy source, format (//) + std::string m_XQSCopySource; + + // Encryption algorithm of the object + std::string m_XQSCopySourceEncryptionCustomerAlgorithm; + + // Encryption key of the object + std::string m_XQSCopySourceEncryptionCustomerKey; + + // MD5sum of encryption key + std::string m_XQSCopySourceEncryptionCustomerKeyMD5; + + // Check whether the Etag of copy source matches the specified value + std::string m_XQSCopySourceIfMatch; + + // Check whether the copy source has been modified since the specified date + std::string m_XQSCopySourceIfModifiedSince; + + // Check whether the Etag of copy source does not matches the specified value + std::string m_XQSCopySourceIfNoneMatch; + + // Check whether the copy source has not been unmodified since the specified date + std::string m_XQSCopySourceIfUnmodifiedSince; + + // Encryption algorithm of the object + std::string m_XQSEncryptionCustomerAlgorithm; + + // Encryption key of the object + std::string m_XQSEncryptionCustomerKey; + + // MD5sum of encryption key + std::string m_XQSEncryptionCustomerKeyMD5; + + std::iostream * m_streambody; +}; +// +-------------------------------------------------------------------- +// | OutputClassHeader +// +-------------------------------------------------------------------- + +typedef QsOutput DeleteBucketOutput; + +typedef QsOutput DeleteBucketCORSOutput; + +typedef QsOutput DeleteBucketExternalMirrorOutput; + +typedef QsOutput DeleteBucketPolicyOutput; + +// DeleteMultipleObjectsOutput presents input for DeleteMultipleObjects. +class QS_SDK_API DeleteMultipleObjectsOutput:public QsOutput +{ + +public: + DeleteMultipleObjectsOutput(QsError err, + Http:: + HttpResponseCode responseCode):QsOutput(err, + responseCode) + { + }; + DeleteMultipleObjectsOutput() + { + }; + + // List of deleted objects + inline void SetDeleted(std::vector < KeyType > Deleted) + { + m_settingFlag |= + SETTING_OUTPUT_DELETE_MULTIPLE_OBJECTS_DELETED_FLAG; + m_Deleted = Deleted; + }; + + inline std::vector < KeyType > GetDeleted() + { + return m_Deleted; + }; + + // Error messages + inline void SetErrors(std::vector < KeyDeleteErrorType > Errors) + { + m_settingFlag |= SETTING_OUTPUT_DELETE_MULTIPLE_OBJECTS_ERRORS_FLAG; + m_Errors = Errors; + }; + + inline std::vector < KeyDeleteErrorType > GetErrors() + { + return m_Errors; + }; + +private: + // List of deleted objects + + std::vector < KeyType > m_Deleted; + + // Error messages + + std::vector < KeyDeleteErrorType > m_Errors; + +}; + +// GetBucketACLOutput presents input for GetBucketACL. +class QS_SDK_API GetBucketACLOutput:public QsOutput +{ + +public: + GetBucketACLOutput(QsError err, + Http::HttpResponseCode responseCode):QsOutput(err, + responseCode) + { + }; + GetBucketACLOutput() + { + }; + + // Bucket ACL rules + inline void SetACL(std::vector < ACLType > ACL) + { + m_settingFlag |= SETTING_OUTPUT_GET_BUCKET_ACL_ACL_FLAG; + m_ACL = ACL; + }; + + inline std::vector < ACLType > GetACL() + { + return m_ACL; + }; + + // Bucket owner + inline void SetOwner(OwnerType Owner) + { + m_settingFlag |= SETTING_OUTPUT_GET_BUCKET_ACL_OWNER_FLAG; + m_Owner = Owner; + }; + + inline OwnerType GetOwner() + { + return m_Owner; + }; + +private: + // Bucket ACL rules + + std::vector < ACLType > m_ACL; + + // Bucket owner + + OwnerType m_Owner; + +}; + +// GetBucketCORSOutput presents input for GetBucketCORS. +class QS_SDK_API GetBucketCORSOutput:public QsOutput +{ + +public: + GetBucketCORSOutput(QsError err, + Http::HttpResponseCode responseCode):QsOutput(err, + responseCode) + { + }; + GetBucketCORSOutput() + { + }; + + // Bucket CORS rules + inline void SetCORSRules(std::vector < CORSRuleType > CORSRules) + { + m_settingFlag |= SETTING_OUTPUT_GET_BUCKET_CORS_CORS_RULES_FLAG; + m_CORSRules = CORSRules; + }; + + inline std::vector < CORSRuleType > GetCORSRules() + { + return m_CORSRules; + }; + +private: + // Bucket CORS rules + + std::vector < CORSRuleType > m_CORSRules; + +}; + +// GetBucketExternalMirrorOutput presents input for GetBucketExternalMirror. +class QS_SDK_API GetBucketExternalMirrorOutput:public QsOutput +{ + +public: + GetBucketExternalMirrorOutput(QsError err, + Http:: + HttpResponseCode + responseCode):QsOutput(err, + responseCode) + { + }; + GetBucketExternalMirrorOutput() + { + }; + + // Source site url + inline void SetSourceSite(std::string SourceSite) + { + m_settingFlag |= + SETTING_OUTPUT_GET_BUCKET_EXTERNAL_MIRROR_SOURCE_SITE_FLAG; + m_SourceSite = SourceSite; + }; + + inline std::string GetSourceSite() + { + return m_SourceSite; + }; + +private: + // Source site url + std::string m_SourceSite; + +}; + +// GetBucketPolicyOutput presents input for GetBucketPolicy. +class QS_SDK_API GetBucketPolicyOutput:public QsOutput +{ + +public: + GetBucketPolicyOutput(QsError err, + Http::HttpResponseCode responseCode):QsOutput(err, + responseCode) + { + }; + GetBucketPolicyOutput() + { + }; + + // Bucket policy statement + inline void SetStatement(std::vector < StatementType > Statement) + { + m_settingFlag |= SETTING_OUTPUT_GET_BUCKET_POLICY_STATEMENT_FLAG; + m_Statement = Statement; + }; + + inline std::vector < StatementType > GetStatement() + { + return m_Statement; + }; + +private: + // Bucket policy statement + + std::vector < StatementType > m_Statement; + +}; + +// GetBucketStatisticsOutput presents input for GetBucketStatistics. +class QS_SDK_API GetBucketStatisticsOutput:public QsOutput +{ + +public: + GetBucketStatisticsOutput(QsError err, + Http:: + HttpResponseCode responseCode):QsOutput(err, + responseCode) + { + }; + GetBucketStatisticsOutput() + { + }; + + // Objects count in the bucket + inline void SetCount(int64_t Count) + { + m_settingFlag |= SETTING_OUTPUT_GET_BUCKET_STATISTICS_COUNT_FLAG; + m_Count = Count; + }; + + inline int64_t GetCount() + { + return m_Count; + }; + + // Bucket created time + inline void SetCreated(std::string Created) + { + m_settingFlag |= SETTING_OUTPUT_GET_BUCKET_STATISTICS_CREATED_FLAG; + m_Created = Created; + }; + + inline std::string GetCreated() + { + return m_Created; + }; + + // QingCloud Zone ID + inline void SetLocation(std::string Location) + { + m_settingFlag |= SETTING_OUTPUT_GET_BUCKET_STATISTICS_LOCATION_FLAG; + m_Location = Location; + }; + + inline std::string GetLocation() + { + return m_Location; + }; + + // Bucket name + inline void SetName(std::string Name) + { + m_settingFlag |= SETTING_OUTPUT_GET_BUCKET_STATISTICS_NAME_FLAG; + m_Name = Name; + }; + + inline std::string GetName() + { + return m_Name; + }; + + // Bucket storage size + inline void SetSize(int64_t Size) + { + m_settingFlag |= SETTING_OUTPUT_GET_BUCKET_STATISTICS_SIZE_FLAG; + m_Size = Size; + }; + + inline int64_t GetSize() + { + return m_Size; + }; + + // Bucket status// Status's available values: active, suspended + inline void SetStatus(std::string Status) + { + m_settingFlag |= SETTING_OUTPUT_GET_BUCKET_STATISTICS_STATUS_FLAG; + m_Status = Status; + }; + + inline std::string GetStatus() + { + return m_Status; + }; + + // URL to access the bucket + inline void SetURL(std::string URL) + { + m_settingFlag |= SETTING_OUTPUT_GET_BUCKET_STATISTICS_URL_FLAG; + m_URL = URL; + }; + + inline std::string GetURL() + { + return m_URL; + }; + +private: + // Objects count in the bucket + int64_t m_Count; + + // Bucket created time + std::string m_Created; + + // QingCloud Zone ID + std::string m_Location; + + // Bucket name + std::string m_Name; + + // Bucket storage size + int64_t m_Size; + + // Bucket status + // Status's available values: active, suspended + std::string m_Status; + + // URL to access the bucket + std::string m_URL; + +}; + +typedef QsOutput HeadBucketOutput; + +// ListMultipartUploadsOutput presents input for ListMultipartUploads. +class QS_SDK_API ListMultipartUploadsOutput:public QsOutput +{ + +public: + ListMultipartUploadsOutput(QsError err, + Http:: + HttpResponseCode responseCode):QsOutput(err, + responseCode) + { + }; + ListMultipartUploadsOutput() + { + }; + + // Other object keys that share common prefixes + inline void SetCommonPrefixes(std::vector < std::string > + CommonPrefixes) + { + m_settingFlag |= + SETTING_OUTPUT_LIST_MULTIPART_UPLOADS_COMMON_PREFIXES_FLAG; + m_CommonPrefixes = CommonPrefixes; + }; + + inline std::vector < std::string > GetCommonPrefixes() + { + return m_CommonPrefixes; + }; + + // Delimiter that specified in request parameters + inline void SetDelimiter(std::string Delimiter) + { + m_settingFlag |= + SETTING_OUTPUT_LIST_MULTIPART_UPLOADS_DELIMITER_FLAG; + m_Delimiter = Delimiter; + }; + + inline std::string GetDelimiter() + { + return m_Delimiter; + }; + + // Limit that specified in request parameters + inline void SetLimit(int Limit) + { + m_settingFlag |= SETTING_OUTPUT_LIST_MULTIPART_UPLOADS_LIMIT_FLAG; + m_Limit = Limit; + }; + + inline int GetLimit() + { + return m_Limit; + }; + + // Marker that specified in request parameters + inline void SetMarker(std::string Marker) + { + m_settingFlag |= SETTING_OUTPUT_LIST_MULTIPART_UPLOADS_MARKER_FLAG; + m_Marker = Marker; + }; + + inline std::string GetMarker() + { + return m_Marker; + }; + + // Bucket name + inline void SetName(std::string Name) + { + m_settingFlag |= SETTING_OUTPUT_LIST_MULTIPART_UPLOADS_NAME_FLAG; + m_Name = Name; + }; + + inline std::string GetName() + { + return m_Name; + }; + + // The last key in uploads list + inline void SetNextKeyMarker(std::string NextKeyMarker) + { + m_settingFlag |= + SETTING_OUTPUT_LIST_MULTIPART_UPLOADS_NEXT_KEY_MARKER_FLAG; + m_NextKeyMarker = NextKeyMarker; + }; + + inline std::string GetNextKeyMarker() + { + return m_NextKeyMarker; + }; + + // The last upload_id in uploads list + inline void SetNextUploadIDMarker(std::string NextUploadIDMarker) + { + m_settingFlag |= + SETTING_OUTPUT_LIST_MULTIPART_UPLOADS_NEXT_UPLOAD_ID_MARKER_FLAG; + m_NextUploadIDMarker = NextUploadIDMarker; + }; + + inline std::string GetNextUploadIDMarker() + { + return m_NextUploadIDMarker; + }; + + // Prefix that specified in request parameters + inline void SetPrefix(std::string Prefix) + { + m_settingFlag |= SETTING_OUTPUT_LIST_MULTIPART_UPLOADS_PREFIX_FLAG; + m_Prefix = Prefix; + }; + + inline std::string GetPrefix() + { + return m_Prefix; + }; + + // Multipart uploads + inline void SetUploads(std::vector < UploadsType > Uploads) + { + m_settingFlag |= SETTING_OUTPUT_LIST_MULTIPART_UPLOADS_UPLOADS_FLAG; + m_Uploads = Uploads; + }; + + inline std::vector < UploadsType > GetUploads() + { + return m_Uploads; + }; + +private: + // Other object keys that share common prefixes + + std::vector < std::string > m_CommonPrefixes; + + // Delimiter that specified in request parameters + std::string m_Delimiter; + + // Limit that specified in request parameters + int m_Limit; + + // Marker that specified in request parameters + std::string m_Marker; + + // Bucket name + std::string m_Name; + + // The last key in uploads list + std::string m_NextKeyMarker; + + // The last upload_id in uploads list + std::string m_NextUploadIDMarker; + + // Prefix that specified in request parameters + std::string m_Prefix; + + // Multipart uploads + + std::vector < UploadsType > m_Uploads; + +}; + +// ListObjectsOutput presents input for ListObjects. +class QS_SDK_API ListObjectsOutput:public QsOutput +{ + +public: + ListObjectsOutput(QsError err, + Http::HttpResponseCode responseCode):QsOutput(err, + responseCode) + { + }; + ListObjectsOutput() + { + }; + + // Other object keys that share common prefixes + inline void SetCommonPrefixes(std::vector < std::string > + CommonPrefixes) + { + m_settingFlag |= SETTING_OUTPUT_LIST_OBJECTS_COMMON_PREFIXES_FLAG; + m_CommonPrefixes = CommonPrefixes; + }; + + inline std::vector < std::string > GetCommonPrefixes() + { + return m_CommonPrefixes; + }; + + // Delimiter that specified in request parameters + inline void SetDelimiter(std::string Delimiter) + { + m_settingFlag |= SETTING_OUTPUT_LIST_OBJECTS_DELIMITER_FLAG; + m_Delimiter = Delimiter; + }; + + inline std::string GetDelimiter() + { + return m_Delimiter; + }; + + // Object keys + inline void SetKeys(std::vector < KeyType > Keys) + { + m_settingFlag |= SETTING_OUTPUT_LIST_OBJECTS_KEYS_FLAG; + m_Keys = Keys; + }; + + inline std::vector < KeyType > GetKeys() + { + return m_Keys; + }; + + // Limit that specified in request parameters + inline void SetLimit(int Limit) + { + m_settingFlag |= SETTING_OUTPUT_LIST_OBJECTS_LIMIT_FLAG; + m_Limit = Limit; + }; + + inline int GetLimit() + { + return m_Limit; + }; + + // Marker that specified in request parameters + inline void SetMarker(std::string Marker) + { + m_settingFlag |= SETTING_OUTPUT_LIST_OBJECTS_MARKER_FLAG; + m_Marker = Marker; + }; + + inline std::string GetMarker() + { + return m_Marker; + }; + + // Bucket name + inline void SetName(std::string Name) + { + m_settingFlag |= SETTING_OUTPUT_LIST_OBJECTS_NAME_FLAG; + m_Name = Name; + }; + + inline std::string GetName() + { + return m_Name; + }; + + // The last key in keys list + inline void SetNextMarker(std::string NextMarker) + { + m_settingFlag |= SETTING_OUTPUT_LIST_OBJECTS_NEXT_MARKER_FLAG; + m_NextMarker = NextMarker; + }; + + inline std::string GetNextMarker() + { + return m_NextMarker; + }; + + // Bucket owner + inline void SetOwner(OwnerType Owner) + { + m_settingFlag |= SETTING_OUTPUT_LIST_OBJECTS_OWNER_FLAG; + m_Owner = Owner; + }; + + inline OwnerType GetOwner() + { + return m_Owner; + }; + + // Prefix that specified in request parameters + inline void SetPrefix(std::string Prefix) + { + m_settingFlag |= SETTING_OUTPUT_LIST_OBJECTS_PREFIX_FLAG; + m_Prefix = Prefix; + }; + + inline std::string GetPrefix() + { + return m_Prefix; + }; + +private: + // Other object keys that share common prefixes + + std::vector < std::string > m_CommonPrefixes; + + // Delimiter that specified in request parameters + std::string m_Delimiter; + + // Object keys + + std::vector < KeyType > m_Keys; + + // Limit that specified in request parameters + int m_Limit; + + // Marker that specified in request parameters + std::string m_Marker; + + // Bucket name + std::string m_Name; + + // The last key in keys list + std::string m_NextMarker; + + // Bucket owner + + OwnerType m_Owner; + + // Prefix that specified in request parameters + std::string m_Prefix; + +}; + +typedef QsOutput PutBucketOutput; + +typedef QsOutput PutBucketACLOutput; + +typedef QsOutput PutBucketCORSOutput; + +typedef QsOutput PutBucketExternalMirrorOutput; + +typedef QsOutput PutBucketPolicyOutput; +// +-------------------------------------------------------------------- +// | OutputClassHeader +// +-------------------------------------------------------------------- + +typedef QsOutput AbortMultipartUploadOutput; + +// CompleteMultipartUploadOutput presents input for CompleteMultipartUpload. +class QS_SDK_API CompleteMultipartUploadOutput:public QsOutput +{ + +public: + CompleteMultipartUploadOutput(QsError err, + Http:: + HttpResponseCode + responseCode):QsOutput(err, + responseCode) + { + }; + CompleteMultipartUploadOutput() + { + }; + + // Encryption algorithm of the object + inline void SetXQSEncryptionCustomerAlgorithm(std:: + string + XQSEncryptionCustomerAlgorithm) + { + m_settingFlag |= + SETTING_OUTPUT_COMPLETE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG; + m_XQSEncryptionCustomerAlgorithm = XQSEncryptionCustomerAlgorithm; + }; + + inline std::string GetXQSEncryptionCustomerAlgorithm() + { + return m_XQSEncryptionCustomerAlgorithm; + }; + +private: + // Encryption algorithm of the object + std::string m_XQSEncryptionCustomerAlgorithm; + +}; + +typedef QsOutput DeleteObjectOutput; + +// GetObjectOutput presents input for GetObject. +class QS_SDK_API GetObjectOutput:public QsOutput +{ + +public: + GetObjectOutput(QsError err, + Http::HttpResponseCode responseCode):QsOutput(err, + responseCode) + { + }; + GetObjectOutput() + { + }; + + // The Cache-Control general-header field is used to specify directives for caching mechanisms in both requests and responses. + inline void SetCacheControl(std::string CacheControl) + { + m_settingFlag |= SETTING_OUTPUT_GET_OBJECT_CACHE_CONTROL_FLAG; + m_CacheControl = CacheControl; + }; + + inline std::string GetCacheControl() + { + return m_CacheControl; + }; + + // In a multipart/form-data body, the HTTP Content-Disposition general header is a header that can be used on the subpart of a multipart body to give information about the field it applies to. + inline void SetContentDisposition(std::string ContentDisposition) + { + m_settingFlag |= SETTING_OUTPUT_GET_OBJECT_CONTENT_DISPOSITION_FLAG; + m_ContentDisposition = ContentDisposition; + }; + + inline std::string GetContentDisposition() + { + return m_ContentDisposition; + }; + + // The Content-Encoding entity header is used to compress the media-type. + inline void SetContentEncoding(std::string ContentEncoding) + { + m_settingFlag |= SETTING_OUTPUT_GET_OBJECT_CONTENT_ENCODING_FLAG; + m_ContentEncoding = ContentEncoding; + }; + + inline std::string GetContentEncoding() + { + return m_ContentEncoding; + }; + + // The Content-Language entity header is used to describe the language(s) intended for the audience. + inline void SetContentLanguage(std::string ContentLanguage) + { + m_settingFlag |= SETTING_OUTPUT_GET_OBJECT_CONTENT_LANGUAGE_FLAG; + m_ContentLanguage = ContentLanguage; + }; + + inline std::string GetContentLanguage() + { + return m_ContentLanguage; + }; + + // Object content length + inline void SetContentLength(int64_t ContentLength) + { + m_settingFlag |= SETTING_OUTPUT_GET_OBJECT_CONTENT_LENGTH_FLAG; + m_ContentLength = ContentLength; + }; + + inline int64_t GetContentLength() + { + return m_ContentLength; + }; + + // Range of response data content + inline void SetContentRange(std::string ContentRange) + { + m_settingFlag |= SETTING_OUTPUT_GET_OBJECT_CONTENT_RANGE_FLAG; + m_ContentRange = ContentRange; + }; + + inline std::string GetContentRange() + { + return m_ContentRange; + }; + + // The Content-Type entity header is used to indicate the media type of the resource. + inline void SetContentType(std::string ContentType) + { + m_settingFlag |= SETTING_OUTPUT_GET_OBJECT_CONTENT_TYPE_FLAG; + m_ContentType = ContentType; + }; + + inline std::string GetContentType() + { + return m_ContentType; + }; + + // MD5sum of the object + inline void SetETag(std::string ETag) + { + m_settingFlag |= SETTING_OUTPUT_GET_OBJECT_ETAG_FLAG; + m_ETag = ETag; + }; + + inline std::string GetETag() + { + return m_ETag; + }; + + // The Expires header contains the date/time after which the response is considered stale. + inline void SetExpires(std::string Expires) + { + m_settingFlag |= SETTING_OUTPUT_GET_OBJECT_EXPIRES_FLAG; + m_Expires = Expires; + }; + + inline std::string GetExpires() + { + return m_Expires; + }; + + inline void SetLastModified(std::string LastModified) + { + m_settingFlag |= SETTING_OUTPUT_GET_OBJECT_LAST_MODIFIED_FLAG; + m_LastModified = LastModified; + }; + + inline std::string GetLastModified() + { + return m_LastModified; + }; + + // Encryption algorithm of the object + inline void SetXQSEncryptionCustomerAlgorithm(std:: + string + XQSEncryptionCustomerAlgorithm) + { + m_settingFlag |= + SETTING_OUTPUT_GET_OBJECT_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG; + m_XQSEncryptionCustomerAlgorithm = XQSEncryptionCustomerAlgorithm; + }; + + inline std::string GetXQSEncryptionCustomerAlgorithm() + { + return m_XQSEncryptionCustomerAlgorithm; + }; + + std::iostream * GetBody() + { + return m_streambody; + }; + void SetBody(std::iostream * streambody) + { + m_streambody = streambody; + }; + +private: + // The Cache-Control general-header field is used to specify directives for caching mechanisms in both requests and responses. + std::string m_CacheControl; + + // In a multipart/form-data body, the HTTP Content-Disposition general header is a header that can be used on the subpart of a multipart body to give information about the field it applies to. + std::string m_ContentDisposition; + + // The Content-Encoding entity header is used to compress the media-type. + std::string m_ContentEncoding; + + // The Content-Language entity header is used to describe the language(s) intended for the audience. + std::string m_ContentLanguage; + + // Object content length + int64_t m_ContentLength; + + // Range of response data content + std::string m_ContentRange; + + // The Content-Type entity header is used to indicate the media type of the resource. + std::string m_ContentType; + + // MD5sum of the object + std::string m_ETag; + + // The Expires header contains the date/time after which the response is considered stale. + std::string m_Expires; + + std::string m_LastModified; + + // Encryption algorithm of the object + std::string m_XQSEncryptionCustomerAlgorithm; + + std::iostream * m_streambody; + +}; + +// HeadObjectOutput presents input for HeadObject. +class QS_SDK_API HeadObjectOutput:public QsOutput +{ + +public: + HeadObjectOutput(QsError err, + Http::HttpResponseCode responseCode):QsOutput(err, + responseCode) + { + }; + HeadObjectOutput() + { + }; + + // Object content length + inline void SetContentLength(int64_t ContentLength) + { + m_settingFlag |= SETTING_OUTPUT_HEAD_OBJECT_CONTENT_LENGTH_FLAG; + m_ContentLength = ContentLength; + }; + + inline int64_t GetContentLength() + { + return m_ContentLength; + }; + + // Object content type + inline void SetContentType(std::string ContentType) + { + m_settingFlag |= SETTING_OUTPUT_HEAD_OBJECT_CONTENT_TYPE_FLAG; + m_ContentType = ContentType; + }; + + inline std::string GetContentType() + { + return m_ContentType; + }; + + // MD5sum of the object + inline void SetETag(std::string ETag) + { + m_settingFlag |= SETTING_OUTPUT_HEAD_OBJECT_ETAG_FLAG; + m_ETag = ETag; + }; + + inline std::string GetETag() + { + return m_ETag; + }; + + inline void SetLastModified(std::string LastModified) + { + m_settingFlag |= SETTING_OUTPUT_HEAD_OBJECT_LAST_MODIFIED_FLAG; + m_LastModified = LastModified; + }; + + inline std::string GetLastModified() + { + return m_LastModified; + }; + + // Encryption algorithm of the object + inline void SetXQSEncryptionCustomerAlgorithm(std:: + string + XQSEncryptionCustomerAlgorithm) + { + m_settingFlag |= + SETTING_OUTPUT_HEAD_OBJECT_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG; + m_XQSEncryptionCustomerAlgorithm = XQSEncryptionCustomerAlgorithm; + }; + + inline std::string GetXQSEncryptionCustomerAlgorithm() + { + return m_XQSEncryptionCustomerAlgorithm; + }; + +private: + // Object content length + int64_t m_ContentLength; + + // Object content type + std::string m_ContentType; + + // MD5sum of the object + std::string m_ETag; + + std::string m_LastModified; + + // Encryption algorithm of the object + std::string m_XQSEncryptionCustomerAlgorithm; + +}; + +// ImageProcessOutput presents input for ImageProcess. +class QS_SDK_API ImageProcessOutput:public QsOutput +{ + +public: + ImageProcessOutput(QsError err, + Http::HttpResponseCode responseCode):QsOutput(err, + responseCode) + { + }; + ImageProcessOutput() + { + }; + + // Object content length + inline void SetContentLength(int64_t ContentLength) + { + m_settingFlag |= SETTING_OUTPUT_IMAGE_PROCESS_CONTENT_LENGTH_FLAG; + m_ContentLength = ContentLength; + }; + + inline int64_t GetContentLength() + { + return m_ContentLength; + }; + + std::iostream * GetBody() + { + return m_streambody; + }; + void SetBody(std::iostream * streambody) + { + m_streambody = streambody; + }; + +private: + // Object content length + int64_t m_ContentLength; + + std::iostream * m_streambody; + +}; + +// InitiateMultipartUploadOutput presents input for InitiateMultipartUpload. +class QS_SDK_API InitiateMultipartUploadOutput:public QsOutput +{ + +public: + InitiateMultipartUploadOutput(QsError err, + Http:: + HttpResponseCode + responseCode):QsOutput(err, + responseCode) + { + }; + InitiateMultipartUploadOutput() + { + }; + + // Encryption algorithm of the object + inline void SetXQSEncryptionCustomerAlgorithm(std:: + string + XQSEncryptionCustomerAlgorithm) + { + m_settingFlag |= + SETTING_OUTPUT_INITIATE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG; + m_XQSEncryptionCustomerAlgorithm = XQSEncryptionCustomerAlgorithm; + }; + + inline std::string GetXQSEncryptionCustomerAlgorithm() + { + return m_XQSEncryptionCustomerAlgorithm; + }; + + // Bucket name + inline void SetBucket(std::string Bucket) + { + m_settingFlag |= + SETTING_OUTPUT_INITIATE_MULTIPART_UPLOAD_BUCKET_FLAG; + m_Bucket = Bucket; + }; + + inline std::string GetBucket() + { + return m_Bucket; + }; + + // Object key + inline void SetKey(std::string Key) + { + m_settingFlag |= SETTING_OUTPUT_INITIATE_MULTIPART_UPLOAD_KEY_FLAG; + m_Key = Key; + }; + + inline std::string GetKey() + { + return m_Key; + }; + + // Object multipart upload ID + inline void SetUploadID(std::string UploadID) + { + m_settingFlag |= + SETTING_OUTPUT_INITIATE_MULTIPART_UPLOAD_UPLOAD_ID_FLAG; + m_UploadID = UploadID; + }; + + inline std::string GetUploadID() + { + return m_UploadID; + }; + +private: + // Encryption algorithm of the object + std::string m_XQSEncryptionCustomerAlgorithm; + + // Bucket name + std::string m_Bucket; + + // Object key + std::string m_Key; + + // Object multipart upload ID + std::string m_UploadID; + +}; + +// ListMultipartOutput presents input for ListMultipart. +class QS_SDK_API ListMultipartOutput:public QsOutput +{ + +public: + ListMultipartOutput(QsError err, + Http::HttpResponseCode responseCode):QsOutput(err, + responseCode) + { + }; + ListMultipartOutput() + { + }; + + // Object multipart count + inline void SetCount(int Count) + { + m_settingFlag |= SETTING_OUTPUT_LIST_MULTIPART_COUNT_FLAG; + m_Count = Count; + }; + + inline int GetCount() + { + return m_Count; + }; + + // Object parts + inline void SetObjectParts(std::vector < ObjectPartType > ObjectParts) + { + m_settingFlag |= SETTING_OUTPUT_LIST_MULTIPART_OBJECT_PARTS_FLAG; + m_ObjectParts = ObjectParts; + }; + + inline std::vector < ObjectPartType > GetObjectParts() + { + return m_ObjectParts; + }; + +private: + // Object multipart count + int m_Count; + + // Object parts + + std::vector < ObjectPartType > m_ObjectParts; + +}; + +// OptionsObjectOutput presents input for OptionsObject. +class QS_SDK_API OptionsObjectOutput:public QsOutput +{ + +public: + OptionsObjectOutput(QsError err, + Http::HttpResponseCode responseCode):QsOutput(err, + responseCode) + { + }; + OptionsObjectOutput() + { + }; + + // Allowed headers + inline void SetAccessControlAllowHeaders(std:: + string + AccessControlAllowHeaders) + { + m_settingFlag |= + SETTING_OUTPUT_OPTIONS_OBJECT_ACCESS_CONTROL_ALLOW_HEADERS_FLAG; + m_AccessControlAllowHeaders = AccessControlAllowHeaders; + }; + + inline std::string GetAccessControlAllowHeaders() + { + return m_AccessControlAllowHeaders; + }; + + // Allowed methods + inline void SetAccessControlAllowMethods(std:: + string + AccessControlAllowMethods) + { + m_settingFlag |= + SETTING_OUTPUT_OPTIONS_OBJECT_ACCESS_CONTROL_ALLOW_METHODS_FLAG; + m_AccessControlAllowMethods = AccessControlAllowMethods; + }; + + inline std::string GetAccessControlAllowMethods() + { + return m_AccessControlAllowMethods; + }; + + // Allowed origin + inline void SetAccessControlAllowOrigin(std:: + string AccessControlAllowOrigin) + { + m_settingFlag |= + SETTING_OUTPUT_OPTIONS_OBJECT_ACCESS_CONTROL_ALLOW_ORIGIN_FLAG; + m_AccessControlAllowOrigin = AccessControlAllowOrigin; + }; + + inline std::string GetAccessControlAllowOrigin() + { + return m_AccessControlAllowOrigin; + }; + + // Expose headers + inline void SetAccessControlExposeHeaders(std:: + string + AccessControlExposeHeaders) + { + m_settingFlag |= + SETTING_OUTPUT_OPTIONS_OBJECT_ACCESS_CONTROL_EXPOSE_HEADERS_FLAG; + m_AccessControlExposeHeaders = AccessControlExposeHeaders; + }; + + inline std::string GetAccessControlExposeHeaders() + { + return m_AccessControlExposeHeaders; + }; + + // Max age + inline void SetAccessControlMaxAge(std::string AccessControlMaxAge) + { + m_settingFlag |= + SETTING_OUTPUT_OPTIONS_OBJECT_ACCESS_CONTROL_MAX_AGE_FLAG; + m_AccessControlMaxAge = AccessControlMaxAge; + }; + + inline std::string GetAccessControlMaxAge() + { + return m_AccessControlMaxAge; + }; + +private: + // Allowed headers + std::string m_AccessControlAllowHeaders; + + // Allowed methods + std::string m_AccessControlAllowMethods; + + // Allowed origin + std::string m_AccessControlAllowOrigin; + + // Expose headers + std::string m_AccessControlExposeHeaders; + + // Max age + std::string m_AccessControlMaxAge; + +}; + +// PutObjectOutput presents input for PutObject. +class QS_SDK_API PutObjectOutput:public QsOutput +{ + +public: + PutObjectOutput(QsError err, + Http::HttpResponseCode responseCode):QsOutput(err, + responseCode) + { + }; + PutObjectOutput() + { + }; + + // MD5sum of the object + inline void SetETag(std::string ETag) + { + m_settingFlag |= SETTING_OUTPUT_PUT_OBJECT_ETAG_FLAG; + m_ETag = ETag; + }; + + inline std::string GetETag() + { + return m_ETag; + }; + + // Encryption algorithm of the object + inline void SetXQSEncryptionCustomerAlgorithm(std:: + string + XQSEncryptionCustomerAlgorithm) + { + m_settingFlag |= + SETTING_OUTPUT_PUT_OBJECT_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG; + m_XQSEncryptionCustomerAlgorithm = XQSEncryptionCustomerAlgorithm; + }; + + inline std::string GetXQSEncryptionCustomerAlgorithm() + { + return m_XQSEncryptionCustomerAlgorithm; + }; + +private: + // MD5sum of the object + std::string m_ETag; + + // Encryption algorithm of the object + std::string m_XQSEncryptionCustomerAlgorithm; + +}; + +// UploadMultipartOutput presents input for UploadMultipart. +class QS_SDK_API UploadMultipartOutput:public QsOutput +{ + +public: + UploadMultipartOutput(QsError err, + Http::HttpResponseCode responseCode):QsOutput(err, + responseCode) + { + }; + UploadMultipartOutput() + { + }; + + // MD5sum of the object + inline void SetETag(std::string ETag) + { + m_settingFlag |= SETTING_OUTPUT_UPLOAD_MULTIPART_ETAG_FLAG; + m_ETag = ETag; + }; + + inline std::string GetETag() + { + return m_ETag; + }; + + // Range of response data content + inline void SetXQSContentCopyRange(std::string XQSContentCopyRange) + { + m_settingFlag |= + SETTING_OUTPUT_UPLOAD_MULTIPART_X_QS_CONTENT_COPY_RANGE_FLAG; + m_XQSContentCopyRange = XQSContentCopyRange; + }; + + inline std::string GetXQSContentCopyRange() + { + return m_XQSContentCopyRange; + }; + + // Encryption algorithm of the object + inline void SetXQSEncryptionCustomerAlgorithm(std:: + string + XQSEncryptionCustomerAlgorithm) + { + m_settingFlag |= + SETTING_OUTPUT_UPLOAD_MULTIPART_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG; + m_XQSEncryptionCustomerAlgorithm = XQSEncryptionCustomerAlgorithm; + }; + + inline std::string GetXQSEncryptionCustomerAlgorithm() + { + return m_XQSEncryptionCustomerAlgorithm; + }; + +private: + // MD5sum of the object + std::string m_ETag; + + // Range of response data content + std::string m_XQSContentCopyRange; + + // Encryption algorithm of the object + std::string m_XQSEncryptionCustomerAlgorithm; + +}; + +// +-------------------------------------------------------------------- +// | Bucket +// +-------------------------------------------------------------------- +class QS_SDK_API Bucket +{ +public: + Bucket(const QsConfig & qsConfig, const std::string & strBucketName, + const std::string & strZone); + + virtual ~ Bucket() + { + }; + + // Delete does Delete a bucket. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/delete.html + QsError DeleteBucket(DeleteBucketInput & input, + DeleteBucketOutput & output); + + // DeleteCORS does Delete CORS information of the bucket. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/cors/delete_cors.html + QsError DeleteBucketCORS(DeleteBucketCORSInput & input, + DeleteBucketCORSOutput & output); + + // DeleteExternalMirror does Delete external mirror of the bucket. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/external_mirror/delete_external_mirror.html + QsError DeleteBucketExternalMirror(DeleteBucketExternalMirrorInput & + input, + DeleteBucketExternalMirrorOutput & + output); + + // DeletePolicy does Delete policy information of the bucket. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/policy/delete_policy.html + QsError DeleteBucketPolicy(DeleteBucketPolicyInput & input, + DeleteBucketPolicyOutput & output); + + // DeleteMultipleObjects does Delete multiple objects from the bucket. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/delete_multiple.html + QsError DeleteMultipleObjects(DeleteMultipleObjectsInput & input, + DeleteMultipleObjectsOutput & output); + + // GetACL does Get ACL information of the bucket. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/get_acl.html + QsError GetBucketACL(GetBucketACLInput & input, + GetBucketACLOutput & output); + + // GetCORS does Get CORS information of the bucket. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/cors/get_cors.html + QsError GetBucketCORS(GetBucketCORSInput & input, + GetBucketCORSOutput & output); + + // GetExternalMirror does Get external mirror of the bucket. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/external_mirror/get_external_mirror.html + QsError GetBucketExternalMirror(GetBucketExternalMirrorInput & input, + GetBucketExternalMirrorOutput & output); + + // GetPolicy does Get policy information of the bucket. + // Documentation URL: https://https://docs.qingcloud.com/qingstor/api/bucket/policy/get_policy.html + QsError GetBucketPolicy(GetBucketPolicyInput & input, + GetBucketPolicyOutput & output); + + // GetStatistics does Get statistics information of the bucket. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/get_stats.html + QsError GetBucketStatistics(GetBucketStatisticsInput & input, + GetBucketStatisticsOutput & output); + + // Head does Check whether the bucket exists and available. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/head.html + QsError HeadBucket(HeadBucketInput & input, HeadBucketOutput & output); + + // ListMultipartUploads does List multipart uploads in the bucket. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/list_multipart_uploads.html + QsError ListMultipartUploads(ListMultipartUploadsInput & input, + ListMultipartUploadsOutput & output); + + // ListObjects does Retrieve the object list in a bucket. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/get.html + QsError ListObjects(ListObjectsInput & input, + ListObjectsOutput & output); + + // Put does Create a new bucket. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/put.html + QsError PutBucket(PutBucketInput & input, PutBucketOutput & output); + + // PutACL does Set ACL information of the bucket. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/put_acl.html + QsError PutBucketACL(PutBucketACLInput & input, + PutBucketACLOutput & output); + + // PutCORS does Set CORS information of the bucket. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/cors/put_cors.html + QsError PutBucketCORS(PutBucketCORSInput & input, + PutBucketCORSOutput & output); + + // PutExternalMirror does Set external mirror of the bucket. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/external_mirror/put_external_mirror.html + QsError PutBucketExternalMirror(PutBucketExternalMirrorInput & input, + PutBucketExternalMirrorOutput & output); + + // PutPolicy does Set policy information of the bucket. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/policy/put_policy.html + QsError PutBucketPolicy(PutBucketPolicyInput & input, + PutBucketPolicyOutput & output); + + // AbortMultipartUpload does Abort multipart upload. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/object/abort_multipart_upload.html + QsError AbortMultipartUpload(std::string objectKey, + AbortMultipartUploadInput & input, + AbortMultipartUploadOutput & output); + + // CompleteMultipartUpload does Complete multipart upload. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/object/complete_multipart_upload.html + QsError CompleteMultipartUpload(std::string objectKey, + CompleteMultipartUploadInput & input, + CompleteMultipartUploadOutput & output); + + // DeleteObject does Delete the object. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/object/delete.html + QsError DeleteObject(std::string objectKey, DeleteObjectInput & input, + DeleteObjectOutput & output); + + // GetObject does Retrieve the object. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/object/get.html + QsError GetObject(std::string objectKey, GetObjectInput & input, + GetObjectOutput & output); + + // HeadObject does Check whether the object exists and available. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/object/head.html + QsError HeadObject(std::string objectKey, HeadObjectInput & input, + HeadObjectOutput & output); + + // ImageProcess does Image process with the action on the object + // Documentation URL: https://docs.qingcloud.com/qingstor/data_process/image_process/index.html + QsError ImageProcess(std::string objectKey, ImageProcessInput & input, + ImageProcessOutput & output); + + // InitiateMultipartUpload does Initial multipart upload on the object. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/object/initiate_multipart_upload.html + QsError InitiateMultipartUpload(std::string objectKey, + InitiateMultipartUploadInput & input, + InitiateMultipartUploadOutput & output); + + // ListMultipart does List object parts. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/object/list_multipart.html + QsError ListMultipart(std::string objectKey, ListMultipartInput & input, + ListMultipartOutput & output); + + // OptionsObject does Check whether the object accepts a origin with method and header. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/object/options.html + QsError OptionsObject(std::string objectKey, OptionsObjectInput & input, + OptionsObjectOutput & output); + + // PutObject does Upload the object. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/object/put.html + QsError PutObject(std::string objectKey, PutObjectInput & input, + PutObjectOutput & output); + + // UploadMultipart does Upload object multipart. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/object/multipart/upload_multipart.html + QsError UploadMultipart(std::string objectKey, + UploadMultipartInput & input, + UploadMultipartOutput & output); + +private: + QsConfig m_qsConfig; + Properties m_properties; + +}; + +} // namespace QingStor diff --git a/include/HttpCommon.h b/include/HttpCommon.h new file mode 100644 index 0000000..9897543 --- /dev/null +++ b/include/HttpCommon.h @@ -0,0 +1,121 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "QsSdkOption.h" +#include "StringUtils.h" +#include +#include +#include + +namespace QingStor +{ +namespace Http +{ +/** + * Http methods. + */ +enum HttpMethod +{ + HTTP_GET, + HTTP_POST, + HTTP_DELETE, + HTTP_PUT, + HTTP_HEAD, + HTTP_OPTIONS, + HTTP_PATCH +}; + +namespace HttpMethodMapper +{ +/** + * Gets the string value of an httpMethod. + */ +QS_SDK_API const char *GetNameForHttpMethod(HttpMethod httpMethod); +} typedef std::pair < std::string, std::string > HeaderValuePair; +typedef std::map < std::string, std::string > HeaderValueCollection; +typedef std::map < std::string, std::string > QueryParamCollection; + +/** + * Enum representing URI scheme. + */ +enum Scheme +{ + HTTP, + HTTPS +}; + +namespace SchemeMapper +{ +/** + * Converts a Scheme instance to a String. + */ +QS_SDK_API const char *ToString(Scheme scheme); +/** +* Converts a string instance to a Scheme. Defaults to https. +*/ +QS_SDK_API Scheme FromString(const char *name); +} enum HttpResponseCode +{ + REQUEST_NOT_MADE = 0, + CONTINUE = 100, + SWITCHING_PROTOCOLS = 101, + PROCESSING = 102, + OK = 200, + CREATED = 201, + ACCEPTED = 202, + NON_AUTHORITATIVE_INFORMATION = 203, + NO_CONTENT = 204, + RESET_CONTENT = 205, + PARTIAL_CONTENT = 206, + MULTI_STATUS = 207, + ALREADY_REPORTED = 208, + IM_USED = 226, + MULTIPLE_CHOICES = 300, + MOVED_PERMANENTLY = 301, + FOUND = 302, + SEE_OTHER = 303, + NOT_MODIFIED = 304, + USE_PROXY = 305, + SWITCH_PROXY = 306, + TEMPORARY_REDIRECT = 307, + PERMANENT_REDIRECT = 308, + BAD_REQUEST = 400, + UNAUTHORIZED_OR_EXPIRED = 401, + DELINQUENT_ACCOUNT = 402, + FORBIDDEN = 403, + NOT_FOUND = 404, + METHOD_NOT_ALLOWED = 405, + CONFLICT = 409, + PRECONDITION_FAILED = 412, + INVALID_RANGE = 416, + TOO_MANY_REQUESTS = 429, + INTERNAL_SERVER_ERROR = 500, + SERVICE_UNAVAILABLE = 503, + GATEWAY_TIMEOUT = 504, + HTTP_VERSION_NOT_SUPPORTED = 505, + VARIANT_ALSO_NEGOTIATES = 506, + INSUFFICIENT_STORAGE = 506, + LOOP_DETECTED = 508, + BANDWIDTH_LIMIT_EXCEEDED = 509, + NOT_EXTENDED = 510, + NETWORK_AUTHENTICATION_REQUIRED = 511, + NETWORK_READ_TIMEOUT = 598, + NETWORK_CONNECT_TIMEOUT = 599 +}; +} +} // namespace QingStor diff --git a/include/QingStor.h b/include/QingStor.h new file mode 100644 index 0000000..3fb3292 --- /dev/null +++ b/include/QingStor.h @@ -0,0 +1,160 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "QsSdkOption.h" +#include "Bucket.h" + +namespace QingStor +{ + +// SDK wide options +struct QS_SDK_API SDKOptions +{ + SDKOptions():initAndCleanupCurl(true), logLevel(None), logPath("") + { + } + // SDK wide options for curl + // If it is being used then we automatically initialize and clean it up. + // If this is a problem for you, set this to false. + bool initAndCleanupCurl; + + // Option for logging level ,defaults to Off + LogLevel logLevel; + + // Option for logging file path, defaults to the path of the executable program. + std::string logPath; +}; + +// This method should be called brfore using the SDK. +QS_SDK_API void InitializeSDK(const SDKOptions & options); + +// This method should be called when you are finished using the SDK. +// Do not call any other SDK methods after calling ShutdownSDK. +QS_SDK_API void ShutdownSDK(const SDKOptions & options); + +// +-------------------------------------------------------------------- +// | InputClassHeader +// +-------------------------------------------------------------------- +// ListBucketsInput presents input for ListBuckets. +class QS_SDK_API ListBucketsInput:public QsInput +{ +public: + ListBucketsInput() + { + }; + + inline bool CheckIfInputIsVaild() + { + int tmpFlag = BASIC_FLAG; + return (tmpFlag == (tmpFlag & m_settingFlag)); + }; + // Limits results to buckets that in the location + + inline void SetLocation(std::string Location) + { + m_settingFlag |= SETTING_INPUT_LIST_BUCKETS_LOCATION_FLAG; + m_Location = Location; + }; + + inline std::string GetLocation() + { + return m_Location; + }; + +private: + // Limits results to buckets that in the location + std::string m_Location; + +}; + +// +-------------------------------------------------------------------- +// | OutputClassHeader +// +-------------------------------------------------------------------- + +// ListBucketsOutput presents input for ListBuckets. +class QS_SDK_API ListBucketsOutput:public QsOutput +{ + +public: + ListBucketsOutput(QsError err, + Http::HttpResponseCode responseCode):QsOutput(err, + responseCode) + { + }; + ListBucketsOutput() + { + }; + + // Buckets information + inline void SetBuckets(std::vector < BucketType > Buckets) + { + m_settingFlag |= SETTING_OUTPUT_LIST_BUCKETS_BUCKETS_FLAG; + m_Buckets = Buckets; + }; + + inline std::vector < BucketType > GetBuckets() + { + return m_Buckets; + }; + + // Bucket count + inline void SetCount(int Count) + { + m_settingFlag |= SETTING_OUTPUT_LIST_BUCKETS_COUNT_FLAG; + m_Count = Count; + }; + + inline int GetCount() + { + return m_Count; + }; + +private: + // Buckets information + + std::vector < BucketType > m_Buckets; + + // Bucket count + int m_Count; + +}; + +// +-------------------------------------------------------------------- +// | QingStorService +// +-------------------------------------------------------------------- + +class QS_SDK_API QingStorService +{ +public: + QingStorService(const QsConfig & qsConfig); + + virtual ~ QingStorService() + { + }; + + // ListBuckets does Retrieve the bucket list. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/service/get.html + QsError ListBuckets(ListBucketsInput & input, + ListBucketsOutput & output); + +private: + QsConfig m_qsConfig; + Properties m_properties; +}; + +} // namespace QingStor diff --git a/include/QsBaseType.h b/include/QsBaseType.h new file mode 100644 index 0000000..2375619 --- /dev/null +++ b/include/QsBaseType.h @@ -0,0 +1,54 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "QsSdkOption.h" +#include +#include +#include + +class QS_SDK_API QsBaseType +{ +public: + QsBaseType():m_settingFlag(0) + { + }; + + virtual ~ QsBaseType() + { + }; + + inline bool IsPropHasBeenSet(int strPropName) + { + if (strPropName & m_settingFlag) // finded + { + return true; + } + else + { + return false; + } + } + + virtual bool CheckIfInputIsVaild() + { + return true; + }; + +protected: + int m_settingFlag; +}; diff --git a/include/QsConfig.h b/include/QsConfig.h new file mode 100644 index 0000000..be7e4b2 --- /dev/null +++ b/include/QsConfig.h @@ -0,0 +1,43 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "QsErrors.h" +#include + +namespace QingStor +{ + +class QsConfig +{ +public: + QsConfig(const std::string & access_key_id = + "", const std::string & secret_access_key = ""); + + QsError LoadConfigFile(const std::string & config_file); + +public: + std::string additionalUserAgent; + std::string accessKeyId; + std::string secretAccessKey; + std::string host; + std::string protocol; + int port; + int connectionRetries; + int timeOutPeriod; // The timeout length of a single attempt, wthich in the unit of second. +}; +} diff --git a/include/QsErrors.h b/include/QsErrors.h new file mode 100644 index 0000000..2637998 --- /dev/null +++ b/include/QsErrors.h @@ -0,0 +1,26 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +typedef enum QsError +{ + QS_ERR_NO_ERROR = 0, // Every is fline, send request sucussfully and get excepted response from QingStor. + QS_ERR_INVAILD_CONFIG_FILE, // There something wrong with your config file. + QS_ERR_NO_REQUIRED_PARAMETER, // The input object lacks some of the parameters that must be filled in . + QS_ERR_SEND_REQUEST_ERROR, // No response has been received. + QS_ERR_UNEXCEPTED_RESPONSE, // Response has been received, but it is not in line with expectations. +} QsError; diff --git a/include/QsSdkOption.h b/include/QsSdkOption.h new file mode 100644 index 0000000..59feb24 --- /dev/null +++ b/include/QsSdkOption.h @@ -0,0 +1,20 @@ +#pragma once + +#define BUILD_C_STYLE_INTERFACE + +#define QS_SDK_API + +#ifdef _WIN32 +#include +#endif + +typedef enum LogLevel +{ + None = 0, + Fatal = 1, + Error = 2, + Warning = 3, + Info = 4, + Debug = 5, + Verbose = 6 +}LogLevel; diff --git a/include/StringUtils.h b/include/StringUtils.h new file mode 100644 index 0000000..ae07411 --- /dev/null +++ b/include/StringUtils.h @@ -0,0 +1,119 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +#pragma once + +#include +#include + +namespace QingStor +{ +namespace Utils +{ + +class StringUtils +{ +public: + static bool HasPrefix(std::string & s, const char *prefix); + + static void Replace(std::string & s, const char *search, + const char *replace); + +#ifdef _WIN32 + /** + * Converts a string to wstring. + */ + static std::wstring ToWString(const char *source); + + /** + * Converts a wstring to string. + */ + static std::string FromWString(const wchar_t * source); +#endif + + /** + * Converts a string to lower case. + */ + static std::string ToLower(const char *source); + + /** + * Converts a string to upper case. + */ + static std::string ToUpper(const char *source); + + /** + * Does a caseless comparison of two strings. + */ + static bool CaselessCompare(const char *value1, const char *value2); + + /** + * URL encodes a string (uses %20 not + for spaces). + */ + static std::string URLEncode(const char *unsafe); + + /** + * URL encodes a double (if it ends up going to scientific notation) otherwise it just returns it as a string. + */ + static std::string URLEncode(double unsafe); + + /** + * Decodes a URL encoded string (will handle both encoding schemes for spaces). + */ + static std::string URLDecode(const char *safe); + + /** + * Splits a string on a delimiter (empty items are excluded). + */ + static std::vector < std::string > + Split(const std::string & toSplit, char splitOn); + + /** + * trim from start + */ + static std::string LTrim(const char *source); + + /** + * trim from end + */ + static std::string RTrim(const char *source); + + /** + * trim from both ends + */ + static std::string Trim(const char *source); + + /** + * convert to int 64 + */ + static long long ConvertToInt64(const char *source); + + /** + * convert to int 32 + */ + static long ConvertToInt32(const char *source); + + /** + * convert to bool + */ + static bool ConvertToBool(const char *source); + + /** + * convert to double + */ + static double ConvertToDouble(const char *source); + +}; +} +} // namespace QingStor diff --git a/include/Types.h b/include/Types.h new file mode 100644 index 0000000..5a39b19 --- /dev/null +++ b/include/Types.h @@ -0,0 +1,130 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "QsSdkOption.h" +#include "QsErrors.h" +#include "HttpCommon.h" +#include +#include +#include +#include "types/ACLType.h" +#include "types/BucketType.h" +#include "types/ConditionType.h" +#include "types/CORSRuleType.h" +#include "types/GranteeType.h" +#include "types/IPAddressType.h" +#include "types/IsNullType.h" +#include "types/KeyType.h" +#include "types/KeyDeleteErrorType.h" +#include "types/NotIPAddressType.h" +#include "types/ObjectPartType.h" +#include "types/OwnerType.h" +#include "types/StatementType.h" +#include "types/StringLikeType.h" +#include "types/StringNotLikeType.h" +#include "types/UploadsType.h" + +namespace QingStor +{ + +struct ResponseErrorInfo +{ + std::string code; + std::string message; + std::string requestID; + std::string url; +}; + +typedef QsBaseType QsInput; + +class QS_SDK_API QsOutput:public QsBaseType +{ +public: + QsOutput():m_responseCode(Http::REQUEST_NOT_MADE) + { + }; + + QsOutput(QsError err, + Http:: + HttpResponseCode responseCode):m_responseCode(responseCode) + { + }; + + virtual ~ QsOutput() + { + }; + + virtual bool IsVaild() + { + return true; + }; + + inline std::string GetRequestID() const + { + return m_requestID; + }; + + inline Http::HttpResponseCode GetResponseCode() const + { + return m_responseCode; + }; + + inline ResponseErrorInfo GetResponseErrInfo() const + { + return m_errorInfo; + }; + + inline void SetRequestID(const std::string & requestID) + { + m_requestID = requestID; + }; + + inline void SetResponseCode(Http::HttpResponseCode responseCode) + { + m_responseCode = responseCode; + }; + + inline void SetResponseErrInfo(const ResponseErrorInfo & errorInfo) + { + m_errorInfo = errorInfo; + }; + +protected: + std::string m_requestID; + + Http::HttpResponseCode m_responseCode; + + ResponseErrorInfo m_errorInfo; +}; + +// Properties presents the service properties. +struct Properties +{ + + // Bucket name + std::string BucketName; // Required + + // Object key + std::string ObjectKey; // Required + + // QingCloud Zone ID + std::string Zone; + +}; + +} // namespace QingStor diff --git a/include/service_with_c_style/QingStorCStyle.h b/include/service_with_c_style/QingStorCStyle.h new file mode 100644 index 0000000..1f62c0b --- /dev/null +++ b/include/service_with_c_style/QingStorCStyle.h @@ -0,0 +1,1138 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "../QsSdkOption.h" +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + void *pQsService; + void *pQsBucket; +} qs_context_handle; + +typedef struct +{ + const char *additional_user_agent; + const char *access_key_id; + const char *secret_access_key; + const char *host; + const char *protocol; + int port; + int conn_retries; + int timeout_period; +} qs_config_t; + +// "init_and_cleanup_curl": SDK wide options for curl +// If it is being used then we automatically initialize and clean it up. +// If this is a problem for you, set this to false. +QS_SDK_API void qs_init_sdk(const char *logfile_path, LogLevel qs_log_level, + unsigned int init_and_cleanup_curl); + +QS_SDK_API void qs_shutdown_sdk(unsigned int init_and_cleanup_curl); + +// Create service and get contex handle which is used with erery SDK API. +QS_SDK_API qs_context_handle qs_create_service(qs_config_t qs_config, + const char *qs_bucket_name, + const char *qs_bucket_zone); + +// Same to fuction "qs_create_service".Specify the path to config file +// instead of providing config structure. +QS_SDK_API qs_context_handle qs_create_service_with_configfile(const char + *qs_config_path, const char + *qs_bucket_name, const char + *qs_bucket_zone); + +// Release contex handle created by functuin "qs_create_service". +QS_SDK_API void qs_release_service(qs_context_handle context_hdl); + +// list_bucketsInput presents input for list_buckets. +typedef struct +{ + //Limits results to buckets that in the location + char *location; +} qs_list_buckets_input_t; + +// list_bucketsInput init function. +void init_list_buckets_input(qs_list_buckets_input_t * input); + +typedef qs_default_input_s qs_delete_bucket_input_t; +// delete_bucketInput init function. +void init_delete_bucket_input(qs_delete_bucket_input_t * input); + +typedef qs_default_input_s qs_delete_bucket_cors_input_t; +// delete_bucket_corsInput init function. +void init_delete_bucket_cors_input(qs_delete_bucket_cors_input_t * input); + +typedef qs_default_input_s qs_delete_bucket_external_mirror_input_t; +// delete_bucket_external_mirrorInput init function. +void init_delete_bucket_external_mirror_input +(qs_delete_bucket_external_mirror_input_t * input); + +typedef qs_default_input_s qs_delete_bucket_policy_input_t; +// delete_bucket_policyInput init function. +void init_delete_bucket_policy_input(qs_delete_bucket_policy_input_t * + input); + +// delete_multiple_objectsInput presents input for delete_multiple_objects. +typedef struct +{ + //Object MD5sum + char *content_md5; // Required + //A list of keys to delete + + qs_list_t *objects; // Required + //Whether to return the list of deleted objects + int *quiet; +} qs_delete_multiple_objects_input_t; + +// delete_multiple_objectsInput init function. +void init_delete_multiple_objects_input(qs_delete_multiple_objects_input_t * + input); + +typedef qs_default_input_s qs_get_bucket_acl_input_t; +// get_bucket_aclInput init function. +void init_get_bucket_acl_input(qs_get_bucket_acl_input_t * input); + +typedef qs_default_input_s qs_get_bucket_cors_input_t; +// get_bucket_corsInput init function. +void init_get_bucket_cors_input(qs_get_bucket_cors_input_t * input); + +typedef qs_default_input_s qs_get_bucket_external_mirror_input_t; +// get_bucket_external_mirrorInput init function. +void init_get_bucket_external_mirror_input +(qs_get_bucket_external_mirror_input_t * input); + +typedef qs_default_input_s qs_get_bucket_policy_input_t; +// get_bucket_policyInput init function. +void init_get_bucket_policy_input(qs_get_bucket_policy_input_t * input); + +typedef qs_default_input_s qs_get_bucket_statistics_input_t; +// get_bucket_statisticsInput init function. +void init_get_bucket_statistics_input(qs_get_bucket_statistics_input_t * + input); + +typedef qs_default_input_s qs_head_bucket_input_t; +// head_bucketInput init function. +void init_head_bucket_input(qs_head_bucket_input_t * input); + +// list_multipart_uploadsInput presents input for list_multipart_uploads. +typedef struct +{ + //Put all keys that share a common prefix into a list + char *delimiter; + //Limit results returned from the first key after key_marker sorted by alphabetical order + char *key_marker; + //Results count limit + int *limit; + //Limits results to keys that begin with the prefix + char *prefix; + //Limit results returned from the first uploading segment after upload_id_marker sorted by the time of upload_id + char *upload_id_marker; +} qs_list_multipart_uploads_input_t; + +// list_multipart_uploadsInput init function. +void init_list_multipart_uploads_input(qs_list_multipart_uploads_input_t * + input); + +// list_objectsInput presents input for list_objects. +typedef struct +{ + //Put all keys that share a common prefix into a list + char *delimiter; + //Results count limit + int *limit; + //Limit results to keys that start at this marker + char *marker; + //Limits results to keys that begin with the prefix + char *prefix; +} qs_list_objects_input_t; + +// list_objectsInput init function. +void init_list_objects_input(qs_list_objects_input_t * input); + +typedef qs_default_input_s qs_put_bucket_input_t; +// put_bucketInput init function. +void init_put_bucket_input(qs_put_bucket_input_t * input); + +// put_bucket_aclInput presents input for put_bucket_acl. +typedef struct +{ + //Bucket ACL rules + + qs_list_t *acl; // Required +} qs_put_bucket_acl_input_t; + +// put_bucket_aclInput init function. +void init_put_bucket_acl_input(qs_put_bucket_acl_input_t * input); + +// put_bucket_corsInput presents input for put_bucket_cors. +typedef struct +{ + //Bucket CORS rules + + qs_list_t *cors_rules; // Required +} qs_put_bucket_cors_input_t; + +// put_bucket_corsInput init function. +void init_put_bucket_cors_input(qs_put_bucket_cors_input_t * input); + +// put_bucket_external_mirrorInput presents input for put_bucket_external_mirror. +typedef struct +{ + //Source site url + char *source_site; // Required +} qs_put_bucket_external_mirror_input_t; + +// put_bucket_external_mirrorInput init function. +void init_put_bucket_external_mirror_input +(qs_put_bucket_external_mirror_input_t * input); + +// put_bucket_policyInput presents input for put_bucket_policy. +typedef struct +{ + //Bucket policy statement + + qs_list_t *statement; // Required +} qs_put_bucket_policy_input_t; + +// put_bucket_policyInput init function. +void init_put_bucket_policy_input(qs_put_bucket_policy_input_t * input); + +// abort_multipart_uploadInput presents input for abort_multipart_upload. +typedef struct +{ + //Object multipart upload ID + char *upload_id; // Required +} qs_abort_multipart_upload_input_t; + +// abort_multipart_uploadInput init function. +void init_abort_multipart_upload_input(qs_abort_multipart_upload_input_t * + input); + +// complete_multipart_uploadInput presents input for complete_multipart_upload. +typedef struct +{ + //Object multipart upload ID + char *upload_id; // Required + //MD5sum of the object part + char *etag; + //Encryption algorithm of the object + char *x_qs_encryption_customer_algorithm; + //Encryption key of the object + char *x_qs_encryption_customer_key; + //MD5sum of encryption key + char *x_qs_encryption_customer_key_md5; + //Object parts + + qs_list_t *object_parts; +} qs_complete_multipart_upload_input_t; + +// complete_multipart_uploadInput init function. +void init_complete_multipart_upload_input +(qs_complete_multipart_upload_input_t * input); + +typedef qs_default_input_s qs_delete_object_input_t; +// delete_objectInput init function. +void init_delete_object_input(qs_delete_object_input_t * input); + +// get_objectInput presents input for get_object. +typedef struct +{ + //Specified the Cache-Control response header + char *response_cache_control; + //Specified the Content-Disposition response header + char *response_content_disposition; + //Specified the Content-Encoding response header + char *response_content_encoding; + //Specified the Content-Language response header + char *response_content_language; + //Specified the Content-Type response header + char *response_content_type; + //Specified the Expires response header + char *response_expires; + //Check whether the ETag matches + char *if_match; + //Check whether the object has been modified + char *if_modified_since; + //Check whether the ETag does not match + char *if_none_match; + //Check whether the object has not been modified + char *if_unmodified_since; + //Specified range of the object + char *range; + //Encryption algorithm of the object + char *x_qs_encryption_customer_algorithm; + //Encryption key of the object + char *x_qs_encryption_customer_key; + //MD5sum of encryption key + char *x_qs_encryption_customer_key_md5; +} qs_get_object_input_t; + +// get_objectInput init function. +void init_get_object_input(qs_get_object_input_t * input); + +// head_objectInput presents input for head_object. +typedef struct +{ + //Check whether the ETag matches + char *if_match; + //Check whether the object has been modified + char *if_modified_since; + //Check whether the ETag does not match + char *if_none_match; + //Check whether the object has not been modified + char *if_unmodified_since; + //Encryption algorithm of the object + char *x_qs_encryption_customer_algorithm; + //Encryption key of the object + char *x_qs_encryption_customer_key; + //MD5sum of encryption key + char *x_qs_encryption_customer_key_md5; +} qs_head_object_input_t; + +// head_objectInput init function. +void init_head_object_input(qs_head_object_input_t * input); + +// image_processInput presents input for image_process. +typedef struct +{ + //Image process action + char *action; // Required + //Specified the Cache-Control response header + char *response_cache_control; + //Specified the Content-Disposition response header + char *response_content_disposition; + //Specified the Content-Encoding response header + char *response_content_encoding; + //Specified the Content-Language response header + char *response_content_language; + //Specified the Content-Type response header + char *response_content_type; + //Specified the Expires response header + char *response_expires; + //Check whether the object has been modified + char *if_modified_since; +} qs_image_process_input_t; + +// image_processInput init function. +void init_image_process_input(qs_image_process_input_t * input); + +// initiate_multipart_uploadInput presents input for initiate_multipart_upload. +typedef struct +{ + //Object content type + char *content_type; + //Encryption algorithm of the object + char *x_qs_encryption_customer_algorithm; + //Encryption key of the object + char *x_qs_encryption_customer_key; + //MD5sum of encryption key + char *x_qs_encryption_customer_key_md5; +} qs_initiate_multipart_upload_input_t; + +// initiate_multipart_uploadInput init function. +void init_initiate_multipart_upload_input +(qs_initiate_multipart_upload_input_t * input); + +// list_multipartInput presents input for list_multipart. +typedef struct +{ + //Limit results count + int *limit; + //Object multipart upload part number + int *part_number_marker; + //Object multipart upload ID + char *upload_id; // Required +} qs_list_multipart_input_t; + +// list_multipartInput init function. +void init_list_multipart_input(qs_list_multipart_input_t * input); + +// options_objectInput presents input for options_object. +typedef struct +{ + //Request headers + char *access_control_request_headers; + //Request method + char *access_control_request_method; // Required + //Request origin + char *origin; // Required +} qs_options_object_input_t; + +// options_objectInput init function. +void init_options_object_input(qs_options_object_input_t * input); + +// put_objectInput presents input for put_object. +typedef struct +{ + //Object content size + long *content_length; // Required + //Object MD5sum + char *content_md5; + //Object content type + char *content_type; + //Used to indicate that particular server behaviors are required by the client + char *expect; + //Copy source, format (//) + char *x_qs_copy_source; + //Encryption algorithm of the object + char *x_qs_copy_source_encryption_customer_algorithm; + //Encryption key of the object + char *x_qs_copy_source_encryption_customer_key; + //MD5sum of encryption key + char *x_qs_copy_source_encryption_customer_key_md5; + //Check whether the copy source matches + char *x_qs_copy_source_if_match; + //Check whether the copy source has been modified + char *x_qs_copy_source_if_modified_since; + //Check whether the copy source does not match + char *x_qs_copy_source_if_none_match; + //Check whether the copy source has not been modified + char *x_qs_copy_source_if_unmodified_since; + //Encryption algorithm of the object + char *x_qs_encryption_customer_algorithm; + //Encryption key of the object + char *x_qs_encryption_customer_key; + //MD5sum of encryption key + char *x_qs_encryption_customer_key_md5; + //Check whether fetch target object has not been modified + char *x_qs_fetch_if_unmodified_since; + //Fetch source, should be a valid url + char *x_qs_fetch_source; + //Move source, format (//) + char *x_qs_move_source; + int64_t *bufLength; + + void *bodybuf; + +} qs_put_object_input_t; + +// put_objectInput init function. +void init_put_object_input(qs_put_object_input_t * input); + +// upload_multipartInput presents input for upload_multipart. +typedef struct +{ + //Object multipart upload part number + int *part_number; // Required + //Object multipart upload ID + char *upload_id; // Required + //Object multipart content length + long *content_length; + //Object multipart content MD5sum + char *content_md5; + //Specify range of the source object + char *x_qs_copy_range; + //Copy source, format (//) + char *x_qs_copy_source; + //Encryption algorithm of the object + char *x_qs_copy_source_encryption_customer_algorithm; + //Encryption key of the object + char *x_qs_copy_source_encryption_customer_key; + //MD5sum of encryption key + char *x_qs_copy_source_encryption_customer_key_md5; + //Check whether the Etag of copy source matches the specified value + char *x_qs_copy_source_if_match; + //Check whether the copy source has been modified since the specified date + char *x_qs_copy_source_if_modified_since; + //Check whether the Etag of copy source does not matches the specified value + char *x_qs_copy_source_if_none_match; + //Check whether the copy source has not been unmodified since the specified date + char *x_qs_copy_source_if_unmodified_since; + //Encryption algorithm of the object + char *x_qs_encryption_customer_algorithm; + //Encryption key of the object + char *x_qs_encryption_customer_key; + //MD5sum of encryption key + char *x_qs_encryption_customer_key_md5; + int64_t *bufLength; + + void *bodybuf; + +} qs_upload_multipart_input_t; + +// upload_multipartInput init function. +void init_upload_multipart_input(qs_upload_multipart_input_t * input); + +typedef struct +{ + //Buckets information + + qs_list_t *buckets; + //Bucket count + int *count; + + int response_code; + + qs_error_info_t error_info; + +} qs_list_buckets_output_t; + +// list_bucketsInput init function. +void release_list_buckets_output(qs_list_buckets_output_t * output); + +typedef qs_default_output_s qs_delete_bucket_output_t; + +// delete_bucketInput init function. +void release_delete_bucket_output(qs_delete_bucket_output_t * output); + +typedef qs_default_output_s qs_delete_bucket_cors_output_t; + +// delete_bucket_corsInput init function. +void release_delete_bucket_cors_output(qs_delete_bucket_cors_output_t * + output); + +typedef qs_default_output_s qs_delete_bucket_external_mirror_output_t; + +// delete_bucket_external_mirrorInput init function. +void release_delete_bucket_external_mirror_output +(qs_delete_bucket_external_mirror_output_t * output); + +typedef qs_default_output_s qs_delete_bucket_policy_output_t; + +// delete_bucket_policyInput init function. +void release_delete_bucket_policy_output(qs_delete_bucket_policy_output_t * + output); + +typedef struct +{ + //List of deleted objects + + qs_list_t *deleted; + //Error messages + + qs_list_t *errors; + + int response_code; + + qs_error_info_t error_info; + +} qs_delete_multiple_objects_output_t; + +// delete_multiple_objectsInput init function. +void release_delete_multiple_objects_output +(qs_delete_multiple_objects_output_t * output); + +typedef struct +{ + //Bucket ACL rules + + qs_list_t *acl; + //Bucket owner + + qs_owner_t *owner; + + int response_code; + + qs_error_info_t error_info; + +} qs_get_bucket_acl_output_t; + +// get_bucket_aclInput init function. +void release_get_bucket_acl_output(qs_get_bucket_acl_output_t * output); + +typedef struct +{ + //Bucket CORS rules + + qs_list_t *cors_rules; + + int response_code; + + qs_error_info_t error_info; + +} qs_get_bucket_cors_output_t; + +// get_bucket_corsInput init function. +void release_get_bucket_cors_output(qs_get_bucket_cors_output_t * output); + +typedef struct +{ + //Source site url + char *source_site; + + int response_code; + + qs_error_info_t error_info; + +} qs_get_bucket_external_mirror_output_t; + +// get_bucket_external_mirrorInput init function. +void release_get_bucket_external_mirror_output +(qs_get_bucket_external_mirror_output_t * output); + +typedef struct +{ + //Bucket policy statement + + qs_list_t *statement; + + int response_code; + + qs_error_info_t error_info; + +} qs_get_bucket_policy_output_t; + +// get_bucket_policyInput init function. +void release_get_bucket_policy_output(qs_get_bucket_policy_output_t * + output); + +typedef struct +{ + //Objects count in the bucket + long *count; + //Bucket created time + char *created; + //QingCloud Zone ID + char *location; + //Bucket name + char *name; + //Bucket storage size + long *size; + //Bucket status//status's available values: active, suspended + char *status; + //URL to access the bucket + char *url; + + int response_code; + + qs_error_info_t error_info; + +} qs_get_bucket_statistics_output_t; + +// get_bucket_statisticsInput init function. +void release_get_bucket_statistics_output(qs_get_bucket_statistics_output_t + * output); + +typedef qs_default_output_s qs_head_bucket_output_t; + +// head_bucketInput init function. +void release_head_bucket_output(qs_head_bucket_output_t * output); + +typedef struct +{ + //Other object keys that share common prefixes + + qs_list_t *common_prefixes; + //Delimiter that specified in request parameters + char *delimiter; + //Limit that specified in request parameters + int *limit; + //Marker that specified in request parameters + char *marker; + //Bucket name + char *name; + //The last key in uploads list + char *next_key_marker; + //The last upload_id in uploads list + char *next_upload_id_marker; + //Prefix that specified in request parameters + char *prefix; + //Multipart uploads + + qs_list_t *uploads; + + int response_code; + + qs_error_info_t error_info; + +} qs_list_multipart_uploads_output_t; + +// list_multipart_uploadsInput init function. +void release_list_multipart_uploads_output +(qs_list_multipart_uploads_output_t * output); + +typedef struct +{ + //Other object keys that share common prefixes + + qs_list_t *common_prefixes; + //Delimiter that specified in request parameters + char *delimiter; + //Object keys + + qs_list_t *keys; + //Limit that specified in request parameters + int *limit; + //Marker that specified in request parameters + char *marker; + //Bucket name + char *name; + //The last key in keys list + char *next_marker; + //Bucket owner + + qs_owner_t *owner; + //Prefix that specified in request parameters + char *prefix; + + int response_code; + + qs_error_info_t error_info; + +} qs_list_objects_output_t; + +// list_objectsInput init function. +void release_list_objects_output(qs_list_objects_output_t * output); + +typedef qs_default_output_s qs_put_bucket_output_t; + +// put_bucketInput init function. +void release_put_bucket_output(qs_put_bucket_output_t * output); + +typedef qs_default_output_s qs_put_bucket_acl_output_t; + +// put_bucket_aclInput init function. +void release_put_bucket_acl_output(qs_put_bucket_acl_output_t * output); + +typedef qs_default_output_s qs_put_bucket_cors_output_t; + +// put_bucket_corsInput init function. +void release_put_bucket_cors_output(qs_put_bucket_cors_output_t * output); + +typedef qs_default_output_s qs_put_bucket_external_mirror_output_t; + +// put_bucket_external_mirrorInput init function. +void release_put_bucket_external_mirror_output +(qs_put_bucket_external_mirror_output_t * output); + +typedef qs_default_output_s qs_put_bucket_policy_output_t; + +// put_bucket_policyInput init function. +void release_put_bucket_policy_output(qs_put_bucket_policy_output_t * + output); + +typedef qs_default_output_s qs_abort_multipart_upload_output_t; + +// abort_multipart_uploadInput init function. +void release_abort_multipart_upload_output +(qs_abort_multipart_upload_output_t * output); + +typedef struct +{ + //Encryption algorithm of the object + char *x_qs_encryption_customer_algorithm; + + int response_code; + + qs_error_info_t error_info; + +} qs_complete_multipart_upload_output_t; + +// complete_multipart_uploadInput init function. +void release_complete_multipart_upload_output +(qs_complete_multipart_upload_output_t * output); + +typedef qs_default_output_s qs_delete_object_output_t; + +// delete_objectInput init function. +void release_delete_object_output(qs_delete_object_output_t * output); + +typedef struct +{ + //The Cache-Control general-header field is used to specify directives for caching mechanisms in both requests and responses. + char *cache_control; + //In a multipart/form-data body, the HTTP Content-Disposition general header is a header that can be used on the subpart of a multipart body to give information about the field it applies to. + char *content_disposition; + //The Content-Encoding entity header is used to compress the media-type. + char *content_encoding; + //The Content-Language entity header is used to describe the language(s) intended for the audience. + char *content_language; + //Object content length + long *content_length; + //Range of response data content + char *content_range; + //The Content-Type entity header is used to indicate the media type of the resource. + char *content_type; + //MD5sum of the object + char *etag; + //The Expires header contains the date/time after which the response is considered stale. + char *expires; + char *last_modified; + //Encryption algorithm of the object + char *x_qs_encryption_customer_algorithm; // The response body + + int64_t *bufLength; + + void *bodybuf; + + int response_code; + + qs_error_info_t error_info; + +} qs_get_object_output_t; + +// get_objectInput init function. +void release_get_object_output(qs_get_object_output_t * output); + +typedef struct +{ + //Object content length + long *content_length; + //Object content type + char *content_type; + //MD5sum of the object + char *etag; + char *last_modified; + //Encryption algorithm of the object + char *x_qs_encryption_customer_algorithm; + + int response_code; + + qs_error_info_t error_info; + +} qs_head_object_output_t; + +// head_objectInput init function. +void release_head_object_output(qs_head_object_output_t * output); + +typedef struct +{ + //Object content length + long *content_length; // The response body + + int64_t *bufLength; + + void *bodybuf; + + int response_code; + + qs_error_info_t error_info; + +} qs_image_process_output_t; + +// image_processInput init function. +void release_image_process_output(qs_image_process_output_t * output); + +typedef struct +{ + //Encryption algorithm of the object + char *x_qs_encryption_customer_algorithm; + //Bucket name + char *bucket; + //Object key + char *key; + //Object multipart upload ID + char *upload_id; + + int response_code; + + qs_error_info_t error_info; + +} qs_initiate_multipart_upload_output_t; + +// initiate_multipart_uploadInput init function. +void release_initiate_multipart_upload_output +(qs_initiate_multipart_upload_output_t * output); + +typedef struct +{ + //Object multipart count + int *count; + //Object parts + + qs_list_t *object_parts; + + int response_code; + + qs_error_info_t error_info; + +} qs_list_multipart_output_t; + +// list_multipartInput init function. +void release_list_multipart_output(qs_list_multipart_output_t * output); + +typedef struct +{ + //Allowed headers + char *access_control_allow_headers; + //Allowed methods + char *access_control_allow_methods; + //Allowed origin + char *access_control_allow_origin; + //Expose headers + char *access_control_expose_headers; + //Max age + char *access_control_max_age; + + int response_code; + + qs_error_info_t error_info; + +} qs_options_object_output_t; + +// options_objectInput init function. +void release_options_object_output(qs_options_object_output_t * output); + +typedef struct +{ + //MD5sum of the object + char *etag; + //Encryption algorithm of the object + char *x_qs_encryption_customer_algorithm; + + int response_code; + + qs_error_info_t error_info; + +} qs_put_object_output_t; + +// put_objectInput init function. +void release_put_object_output(qs_put_object_output_t * output); + +typedef struct +{ + //MD5sum of the object + char *etag; + //Range of response data content + char *x_qs_content_copy_range; + //Encryption algorithm of the object + char *x_qs_encryption_customer_algorithm; + + int response_code; + + qs_error_info_t error_info; + +} qs_upload_multipart_output_t; + +// upload_multipartInput init function. +void release_upload_multipart_output(qs_upload_multipart_output_t * output); // list_buckets does Retrieve the bucket list. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/service/get.html +QsError QS_SDK_API qs_list_buckets(qs_list_buckets_input_t * input, + qs_list_buckets_output_t * output, + qs_context_handle context_hdl); + +// delete_bucket does Delete a bucket. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/delete.html +QsError QS_SDK_API qs_delete_bucket(qs_delete_bucket_input_t * input, + qs_delete_bucket_output_t * output, + qs_context_handle context_hdl); + +// delete_bucket_cors does Delete CORS information of the bucket. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/cors/delete_cors.html +QsError QS_SDK_API qs_delete_bucket_cors(qs_delete_bucket_cors_input_t * + input, + qs_delete_bucket_cors_output_t * + output, + qs_context_handle context_hdl); + +// delete_bucket_external_mirror does Delete external mirror of the bucket. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/external_mirror/delete_external_mirror.html +QsError QS_SDK_API +qs_delete_bucket_external_mirror +(qs_delete_bucket_external_mirror_input_t * input, + qs_delete_bucket_external_mirror_output_t * output, + qs_context_handle context_hdl); + +// delete_bucket_policy does Delete policy information of the bucket. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/policy/delete_policy.html +QsError QS_SDK_API qs_delete_bucket_policy(qs_delete_bucket_policy_input_t * + input, + qs_delete_bucket_policy_output_t + * output, + qs_context_handle context_hdl); + +// delete_multiple_objects does Delete multiple objects from the bucket. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/delete_multiple.html +QsError QS_SDK_API +qs_delete_multiple_objects(qs_delete_multiple_objects_input_t * input, + qs_delete_multiple_objects_output_t * output, + qs_context_handle context_hdl); + +// get_bucket_acl does Get ACL information of the bucket. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/get_acl.html +QsError QS_SDK_API qs_get_bucket_acl(qs_get_bucket_acl_input_t * input, + qs_get_bucket_acl_output_t * output, + qs_context_handle context_hdl); + +// get_bucket_cors does Get CORS information of the bucket. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/cors/get_cors.html +QsError QS_SDK_API qs_get_bucket_cors(qs_get_bucket_cors_input_t * input, + qs_get_bucket_cors_output_t * output, + qs_context_handle context_hdl); + +// get_bucket_external_mirror does Get external mirror of the bucket. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/external_mirror/get_external_mirror.html +QsError QS_SDK_API +qs_get_bucket_external_mirror(qs_get_bucket_external_mirror_input_t * + input, + qs_get_bucket_external_mirror_output_t * + output, qs_context_handle context_hdl); + +// get_bucket_policy does Get policy information of the bucket. +// Documentation URL: https://https://docs.qingcloud.com/qingstor/api/bucket/policy/get_policy.html +QsError QS_SDK_API qs_get_bucket_policy(qs_get_bucket_policy_input_t * + input, + qs_get_bucket_policy_output_t * + output, + qs_context_handle context_hdl); + +// get_bucket_statistics does Get statistics information of the bucket. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/get_stats.html +QsError QS_SDK_API qs_get_bucket_statistics(qs_get_bucket_statistics_input_t + * input, + qs_get_bucket_statistics_output_t + * output, + qs_context_handle context_hdl); + +// head_bucket does Check whether the bucket exists and available. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/head.html +QsError QS_SDK_API qs_head_bucket(qs_head_bucket_input_t * input, + qs_head_bucket_output_t * output, + qs_context_handle context_hdl); + +// list_multipart_uploads does List multipart uploads in the bucket. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/list_multipart_uploads.html +QsError QS_SDK_API +qs_list_multipart_uploads(qs_list_multipart_uploads_input_t * input, + qs_list_multipart_uploads_output_t * output, + qs_context_handle context_hdl); + +// list_objects does Retrieve the object list in a bucket. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/get.html +QsError QS_SDK_API qs_list_objects(qs_list_objects_input_t * input, + qs_list_objects_output_t * output, + qs_context_handle context_hdl); + +// put_bucket does Create a new bucket. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/put.html +QsError QS_SDK_API qs_put_bucket(qs_put_bucket_input_t * input, + qs_put_bucket_output_t * output, + qs_context_handle context_hdl); + +// put_bucket_acl does Set ACL information of the bucket. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/put_acl.html +QsError QS_SDK_API qs_put_bucket_acl(qs_put_bucket_acl_input_t * input, + qs_put_bucket_acl_output_t * output, + qs_context_handle context_hdl); + +// put_bucket_cors does Set CORS information of the bucket. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/cors/put_cors.html +QsError QS_SDK_API qs_put_bucket_cors(qs_put_bucket_cors_input_t * input, + qs_put_bucket_cors_output_t * output, + qs_context_handle context_hdl); + +// put_bucket_external_mirror does Set external mirror of the bucket. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/external_mirror/put_external_mirror.html +QsError QS_SDK_API +qs_put_bucket_external_mirror(qs_put_bucket_external_mirror_input_t * + input, + qs_put_bucket_external_mirror_output_t * + output, qs_context_handle context_hdl); + +// put_bucket_policy does Set policy information of the bucket. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/bucket/policy/put_policy.html +QsError QS_SDK_API qs_put_bucket_policy(qs_put_bucket_policy_input_t * + input, + qs_put_bucket_policy_output_t * + output, + qs_context_handle context_hdl); + +// abort_multipart_upload does Abort multipart upload. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/object/abort_multipart_upload.html +QsError QS_SDK_API qs_abort_multipart_upload(char *objectKey, + qs_abort_multipart_upload_input_t + * input, + qs_abort_multipart_upload_output_t + * output, + qs_context_handle context_hdl); + +// complete_multipart_upload does Complete multipart upload. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/object/complete_multipart_upload.html +QsError QS_SDK_API qs_complete_multipart_upload(char *objectKey, + qs_complete_multipart_upload_input_t + * input, + qs_complete_multipart_upload_output_t + * output, + qs_context_handle + context_hdl); + +// delete_object does Delete the object. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/object/delete.html +QsError QS_SDK_API qs_delete_object(char *objectKey, + qs_delete_object_input_t * input, + qs_delete_object_output_t * output, + qs_context_handle context_hdl); + +// get_object does Retrieve the object. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/object/get.html +QsError QS_SDK_API qs_get_object(char *objectKey, + qs_get_object_input_t * input, + qs_get_object_output_t * output, + qs_context_handle context_hdl); + +// head_object does Check whether the object exists and available. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/object/head.html +QsError QS_SDK_API qs_head_object(char *objectKey, + qs_head_object_input_t * input, + qs_head_object_output_t * output, + qs_context_handle context_hdl); + +// image_process does Image process with the action on the object +// Documentation URL: https://docs.qingcloud.com/qingstor/data_process/image_process/index.html +QsError QS_SDK_API qs_image_process(char *objectKey, + qs_image_process_input_t * input, + qs_image_process_output_t * output, + qs_context_handle context_hdl); + +// initiate_multipart_upload does Initial multipart upload on the object. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/object/initiate_multipart_upload.html +QsError QS_SDK_API qs_initiate_multipart_upload(char *objectKey, + qs_initiate_multipart_upload_input_t + * input, + qs_initiate_multipart_upload_output_t + * output, + qs_context_handle + context_hdl); + +// list_multipart does List object parts. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/object/list_multipart.html +QsError QS_SDK_API qs_list_multipart(char *objectKey, + qs_list_multipart_input_t * input, + qs_list_multipart_output_t * output, + qs_context_handle context_hdl); + +// options_object does Check whether the object accepts a origin with method and header. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/object/options.html +QsError QS_SDK_API qs_options_object(char *objectKey, + qs_options_object_input_t * input, + qs_options_object_output_t * output, + qs_context_handle context_hdl); + +// put_object does Upload the object. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/object/put.html +QsError QS_SDK_API qs_put_object(char *objectKey, + qs_put_object_input_t * input, + qs_put_object_output_t * output, + qs_context_handle context_hdl); + +// upload_multipart does Upload object multipart. +// Documentation URL: https://docs.qingcloud.com/qingstor/api/object/multipart/upload_multipart.html +QsError QS_SDK_API qs_upload_multipart(char *objectKey, + qs_upload_multipart_input_t * input, + qs_upload_multipart_output_t * + output, + qs_context_handle context_hdl); + +#ifdef __cplusplus +} +#endif diff --git a/include/service_with_c_style/QsList.h b/include/service_with_c_style/QsList.h new file mode 100644 index 0000000..9cddd69 --- /dev/null +++ b/include/service_with_c_style/QsList.h @@ -0,0 +1,101 @@ + +#ifndef _QS_LIST_H +#define _QS_LIST_H + +#include +#include +#include +#include "../QsSdkOption.h" + +typedef struct qs_list_s qs_list_t; + +struct qs_list_s +{ + qs_list_t *next, *prev; +}; + +#define qs_list_head_init(name) \ + { \ + &(name), &(name) \ + } + +#define qs_list_init(ptr) \ + do \ + { \ + (ptr)->next = (ptr); \ + (ptr)->prev = (ptr); \ + } while (0) + +// list head to add it before +static void qs_list_append(qs_list_t * new_node, qs_list_t * listhead) +{ + new_node->prev = listhead->prev; + listhead->prev->next = new_node; + listhead->prev = new_node; + new_node->next = listhead; +} + +// deletes entry from list +static void qs_list_del(qs_list_t * entry) +{ + entry->next->prev = entry->prev; + entry->prev->next = entry->next; + qs_list_init(entry); +} + +// tests whether a list is empty +static int qs_is_list_empty(const qs_list_t * list_head) +{ + return (list_head->next == list_head); +} + +// get last +#define qs_list_get_last(list, type) qs_is_list_empty(list) ? NULL : qs_list_entry((list)->prev, type) + +// get first +#define qs_list_get_first(list, type) qs_is_list_empty(list) ? NULL : qs_list_entry((list)->next, type) + +#define qs_list_entry(ptr, type) (type *)((char *)ptr - offsetof(type, node)) + +// traversing +#define qs_list_for_each_entry(postp, pos, head) for (pos = qs_list_entry((head)->next, postp); &pos->node != (head); pos = qs_list_entry(pos->node.next, postp)) + +#define qs_list_for_each_entry_safe(postp, pos, n, head) for (pos = qs_list_entry((head)->next, postp), n = qs_list_entry(pos->node.next, postp); &pos->node != (head); pos = n, n = qs_list_entry(n->node.next, postp)) + +typedef struct +{ + qs_list_t node; + char *content; +} qs_string_item_t; + +typedef struct +{ + qs_list_t node; + int *content; +} qs_bool_item_t; + +typedef struct +{ + qs_list_t node; + int *content; +} qs_int_item_t; + +typedef struct +{ + qs_list_t node; + char *content; +} qs_time_item_t; + +typedef struct +{ + qs_list_t node; + int64_t *content; +} qs_long_item_t; + +typedef struct +{ + int64_t size; + void *buffer; +} qs_buffer_t; + +#endif diff --git a/include/service_with_c_style/Types.h b/include/service_with_c_style/Types.h new file mode 100644 index 0000000..51e0db9 --- /dev/null +++ b/include/service_with_c_style/Types.h @@ -0,0 +1,56 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "../QsSdkOption.h" +#include "../QsErrors.h" +#include "types/ACLType.h" +#include "types/BucketType.h" +#include "types/ConditionType.h" +#include "types/CORSRuleType.h" +#include "types/GranteeType.h" +#include "types/IPAddressType.h" +#include "types/IsNullType.h" +#include "types/KeyType.h" +#include "types/KeyDeleteErrorType.h" +#include "types/NotIPAddressType.h" +#include "types/ObjectPartType.h" +#include "types/OwnerType.h" +#include "types/StatementType.h" +#include "types/StringLikeType.h" +#include "types/StringNotLikeType.h" +#include "types/UploadsType.h" + +typedef struct +{ + char *code; + char *message; + char *request_id; + char *url; +} qs_error_info_t; + +typedef struct +{ + int response_code; + qs_error_info_t error_info; + +} qs_default_output_s; + +typedef struct +{ + int response_code; +} qs_default_input_s; diff --git a/include/service_with_c_style/types/ACLType.h b/include/service_with_c_style/types/ACLType.h new file mode 100644 index 0000000..89490d1 --- /dev/null +++ b/include/service_with_c_style/types/ACLType.h @@ -0,0 +1,52 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +#pragma once + +#include "../QsList.h" +// Headers of CustomizedType. +#include "GranteeType.h" +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + + qs_grantee_t *grantee; // Required + //Permission for this grantee//permission's available values: READ, WRITE, FULL_CONTROL + char *permission; // Required + + int setting_flag; +} qs_acl_t; + +typedef struct +{ + + qs_list_t node; + + qs_acl_t *content; + +} qs_acl_item_t; + +// acl init function. +void init_acl(qs_acl_t * input); + +// acl release function. +void release_acl(qs_acl_t * output); + +#ifdef __cplusplus +}; +#endif diff --git a/include/service_with_c_style/types/BucketType.h b/include/service_with_c_style/types/BucketType.h new file mode 100644 index 0000000..dd66464 --- /dev/null +++ b/include/service_with_c_style/types/BucketType.h @@ -0,0 +1,56 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +#pragma once + +#include "../QsList.h" +// Headers of CustomizedType. +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + + //Created time of the bucket + char *created; + //QingCloud Zone ID + char *location; + //Bucket name + char *name; + //URL to access the bucket + char *url; + + int setting_flag; +} qs_bucket_t; + +typedef struct +{ + + qs_list_t node; + + qs_bucket_t *content; + +} qs_bucket_item_t; + +// bucket init function. +void init_bucket(qs_bucket_t * input); + +// bucket release function. +void release_bucket(qs_bucket_t * output); + +#ifdef __cplusplus +}; +#endif diff --git a/include/service_with_c_style/types/CORSRuleType.h b/include/service_with_c_style/types/CORSRuleType.h new file mode 100644 index 0000000..844dc6f --- /dev/null +++ b/include/service_with_c_style/types/CORSRuleType.h @@ -0,0 +1,84 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +#pragma once + +#include "../QsList.h" +// Headers of CustomizedType. +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + + //Allowed headers + + qs_list_t *allowed_headers; + //Allowed methods + + qs_list_t *allowed_methods; // Required + //Allowed origin + char *allowed_origin; // Required + //Expose headers + + qs_list_t *expose_headers; + //Max age seconds + int *max_age_seconds; + + int setting_flag; +} qs_cors_rule_t; + +typedef struct +{ + + qs_list_t node; + + qs_cors_rule_t *content; + +} qs_cors_rule_item_t; + +typedef struct +{ + qs_list_t node; + + char *content; + +} qs_cors_rule_allowed_headers_item_t; +typedef struct +{ + qs_list_t node; + + char *content; + +} qs_cors_rule_allowed_methods_item_t; + +typedef struct +{ + qs_list_t node; + + char *content; + +} qs_cors_rule_expose_headers_item_t; + +// cors_rule init function. +void init_cors_rule(qs_cors_rule_t * input); + +// cors_rule release function. +void release_cors_rule(qs_cors_rule_t * output); + +#ifdef __cplusplus +}; +#endif diff --git a/include/service_with_c_style/types/ConditionType.h b/include/service_with_c_style/types/ConditionType.h new file mode 100644 index 0000000..37a3d4a --- /dev/null +++ b/include/service_with_c_style/types/ConditionType.h @@ -0,0 +1,62 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +#pragma once + +#include "../QsList.h" +// Headers of CustomizedType. +#include "IPAddressType.h" +#include "IsNullType.h" +#include "NotIPAddressType.h" +#include "StringLikeType.h" +#include "StringNotLikeType.h" +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + + qs_ip_address_t *ip_address; + + qs_is_null_t *is_null; + + qs_not_ip_address_t *not_ip_address; + + qs_string_like_t *string_like; + + qs_string_not_like_t *string_not_like; + + int setting_flag; +} qs_condition_t; + +typedef struct +{ + + qs_list_t node; + + qs_condition_t *content; + +} qs_condition_item_t; + +// condition init function. +void init_condition(qs_condition_t * input); + +// condition release function. +void release_condition(qs_condition_t * output); + +#ifdef __cplusplus +}; +#endif diff --git a/include/service_with_c_style/types/GranteeType.h b/include/service_with_c_style/types/GranteeType.h new file mode 100644 index 0000000..276a303 --- /dev/null +++ b/include/service_with_c_style/types/GranteeType.h @@ -0,0 +1,54 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +#pragma once + +#include "../QsList.h" +// Headers of CustomizedType. +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + + //Grantee user ID + char *id; + //Grantee group name + char *name; + //Grantee type//type's available values: user, group + char *type; // Required + + int setting_flag; +} qs_grantee_t; + +typedef struct +{ + + qs_list_t node; + + qs_grantee_t *content; + +} qs_grantee_item_t; + +// grantee init function. +void init_grantee(qs_grantee_t * input); + +// grantee release function. +void release_grantee(qs_grantee_t * output); + +#ifdef __cplusplus +}; +#endif diff --git a/include/service_with_c_style/types/IPAddressType.h b/include/service_with_c_style/types/IPAddressType.h new file mode 100644 index 0000000..8c3a62b --- /dev/null +++ b/include/service_with_c_style/types/IPAddressType.h @@ -0,0 +1,59 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +#pragma once + +#include "../QsList.h" +// Headers of CustomizedType. +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + + //Source IP + + qs_list_t *source_ip; + + int setting_flag; +} qs_ip_address_t; + +typedef struct +{ + + qs_list_t node; + + qs_ip_address_t *content; + +} qs_ip_address_item_t; + +typedef struct +{ + qs_list_t node; + + char *content; + +} qs_ip_address_source_ip_item_t; + +// ip_address init function. +void init_ip_address(qs_ip_address_t * input); + +// ip_address release function. +void release_ip_address(qs_ip_address_t * output); + +#ifdef __cplusplus +}; +#endif diff --git a/include/service_with_c_style/types/IsNullType.h b/include/service_with_c_style/types/IsNullType.h new file mode 100644 index 0000000..f25a075 --- /dev/null +++ b/include/service_with_c_style/types/IsNullType.h @@ -0,0 +1,50 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +#pragma once + +#include "../QsList.h" +// Headers of CustomizedType. +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + + //Refer url + int *referer; + + int setting_flag; +} qs_is_null_t; + +typedef struct +{ + + qs_list_t node; + + qs_is_null_t *content; + +} qs_is_null_item_t; + +// is_null init function. +void init_is_null(qs_is_null_t * input); + +// is_null release function. +void release_is_null(qs_is_null_t * output); + +#ifdef __cplusplus +}; +#endif diff --git a/include/service_with_c_style/types/KeyDeleteErrorType.h b/include/service_with_c_style/types/KeyDeleteErrorType.h new file mode 100644 index 0000000..78aa4de --- /dev/null +++ b/include/service_with_c_style/types/KeyDeleteErrorType.h @@ -0,0 +1,55 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +#pragma once + +#include "../QsList.h" +// Headers of CustomizedType. +#include "KeyType.h" +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + + //Error code + char *code; + //Object key + char *key; + //Error message + char *message; + + int setting_flag; +} qs_key_delete_error_t; + +typedef struct +{ + + qs_list_t node; + + qs_key_delete_error_t *content; + +} qs_key_delete_error_item_t; + +// key_delete_error init function. +void init_key_delete_error(qs_key_delete_error_t * input); + +// key_delete_error release function. +void release_key_delete_error(qs_key_delete_error_t * output); + +#ifdef __cplusplus +}; +#endif diff --git a/include/service_with_c_style/types/KeyType.h b/include/service_with_c_style/types/KeyType.h new file mode 100644 index 0000000..4787889 --- /dev/null +++ b/include/service_with_c_style/types/KeyType.h @@ -0,0 +1,63 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +#pragma once + +#include "../QsList.h" +// Headers of CustomizedType. +#include "KeyType.h" +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + + //Object created time + char *created; + //Whether this key is encrypted + int *encrypted; + //MD5sum of the object + char *etag; + //Object key + char *key; + //MIME type of the object + char *mime_type; + //Last modified time in unix time format + int *modified; + //Object content size + long *size; + + int setting_flag; +} qs_key_t; + +typedef struct +{ + + qs_list_t node; + + qs_key_t *content; + +} qs_key_item_t; + +// key init function. +void init_key(qs_key_t * input); + +// key release function. +void release_key(qs_key_t * output); + +#ifdef __cplusplus +}; +#endif diff --git a/include/service_with_c_style/types/NotIPAddressType.h b/include/service_with_c_style/types/NotIPAddressType.h new file mode 100644 index 0000000..bd6e37b --- /dev/null +++ b/include/service_with_c_style/types/NotIPAddressType.h @@ -0,0 +1,59 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +#pragma once + +#include "../QsList.h" +// Headers of CustomizedType. +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + + //Source IP + + qs_list_t *source_ip; + + int setting_flag; +} qs_not_ip_address_t; + +typedef struct +{ + + qs_list_t node; + + qs_not_ip_address_t *content; + +} qs_not_ip_address_item_t; + +typedef struct +{ + qs_list_t node; + + char *content; + +} qs_not_ip_address_source_ip_item_t; + +// not_ip_address init function. +void init_not_ip_address(qs_not_ip_address_t * input); + +// not_ip_address release function. +void release_not_ip_address(qs_not_ip_address_t * output); + +#ifdef __cplusplus +}; +#endif diff --git a/include/service_with_c_style/types/ObjectPartType.h b/include/service_with_c_style/types/ObjectPartType.h new file mode 100644 index 0000000..6ec5ba2 --- /dev/null +++ b/include/service_with_c_style/types/ObjectPartType.h @@ -0,0 +1,56 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +#pragma once + +#include "../QsList.h" +// Headers of CustomizedType. +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + + //Object part created time + char *created; + //MD5sum of the object part + char *etag; + //Object part number + int *part_number; // Required + //Object part size + long *size; + + int setting_flag; +} qs_object_part_t; + +typedef struct +{ + + qs_list_t node; + + qs_object_part_t *content; + +} qs_object_part_item_t; + +// object_part init function. +void init_object_part(qs_object_part_t * input); + +// object_part release function. +void release_object_part(qs_object_part_t * output); + +#ifdef __cplusplus +}; +#endif diff --git a/include/service_with_c_style/types/OwnerType.h b/include/service_with_c_style/types/OwnerType.h new file mode 100644 index 0000000..ed15f69 --- /dev/null +++ b/include/service_with_c_style/types/OwnerType.h @@ -0,0 +1,52 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +#pragma once + +#include "../QsList.h" +// Headers of CustomizedType. +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + + //User ID + char *id; + //Username + char *name; + + int setting_flag; +} qs_owner_t; + +typedef struct +{ + + qs_list_t node; + + qs_owner_t *content; + +} qs_owner_item_t; + +// owner init function. +void init_owner(qs_owner_t * input); + +// owner release function. +void release_owner(qs_owner_t * output); + +#ifdef __cplusplus +}; +#endif diff --git a/include/service_with_c_style/types/StatementType.h b/include/service_with_c_style/types/StatementType.h new file mode 100644 index 0000000..cbccc1c --- /dev/null +++ b/include/service_with_c_style/types/StatementType.h @@ -0,0 +1,87 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +#pragma once + +#include "../QsList.h" +// Headers of CustomizedType. +#include "ConditionType.h" +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + + //QingStor API methods + + qs_list_t *action; // Required + + qs_condition_t *condition; + //Statement effect//effect's available values: allow, deny + char *effect; // Required + //Bucket policy id, must be unique + char *id; // Required + //The resources to apply bucket policy + + qs_list_t *resource; + //The user to apply bucket policy + + qs_list_t *user; // Required + + int setting_flag; +} qs_statement_t; + +typedef struct +{ + + qs_list_t node; + + qs_statement_t *content; + +} qs_statement_item_t; + +typedef struct +{ + qs_list_t node; + + char *content; + +} qs_statement_action_item_t; + +typedef struct +{ + qs_list_t node; + + char *content; + +} qs_statement_resource_item_t; +typedef struct +{ + qs_list_t node; + + char *content; + +} qs_statement_user_item_t; + +// statement init function. +void init_statement(qs_statement_t * input); + +// statement release function. +void release_statement(qs_statement_t * output); + +#ifdef __cplusplus +}; +#endif diff --git a/include/service_with_c_style/types/StringLikeType.h b/include/service_with_c_style/types/StringLikeType.h new file mode 100644 index 0000000..751c54f --- /dev/null +++ b/include/service_with_c_style/types/StringLikeType.h @@ -0,0 +1,59 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +#pragma once + +#include "../QsList.h" +// Headers of CustomizedType. +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + + //Refer url + + qs_list_t *referer; + + int setting_flag; +} qs_string_like_t; + +typedef struct +{ + + qs_list_t node; + + qs_string_like_t *content; + +} qs_string_like_item_t; + +typedef struct +{ + qs_list_t node; + + char *content; + +} qs_string_like_referer_item_t; + +// string_like init function. +void init_string_like(qs_string_like_t * input); + +// string_like release function. +void release_string_like(qs_string_like_t * output); + +#ifdef __cplusplus +}; +#endif diff --git a/include/service_with_c_style/types/StringNotLikeType.h b/include/service_with_c_style/types/StringNotLikeType.h new file mode 100644 index 0000000..603ade3 --- /dev/null +++ b/include/service_with_c_style/types/StringNotLikeType.h @@ -0,0 +1,59 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +#pragma once + +#include "../QsList.h" +// Headers of CustomizedType. +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + + //Refer url + + qs_list_t *referer; + + int setting_flag; +} qs_string_not_like_t; + +typedef struct +{ + + qs_list_t node; + + qs_string_not_like_t *content; + +} qs_string_not_like_item_t; + +typedef struct +{ + qs_list_t node; + + char *content; + +} qs_string_not_like_referer_item_t; + +// string_not_like init function. +void init_string_not_like(qs_string_not_like_t * input); + +// string_not_like release function. +void release_string_not_like(qs_string_not_like_t * output); + +#ifdef __cplusplus +}; +#endif diff --git a/include/service_with_c_style/types/UploadsType.h b/include/service_with_c_style/types/UploadsType.h new file mode 100644 index 0000000..2aae92b --- /dev/null +++ b/include/service_with_c_style/types/UploadsType.h @@ -0,0 +1,55 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +#pragma once + +#include "../QsList.h" +// Headers of CustomizedType. +#include "KeyType.h" +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + + //Object part created time + char *created; + //Object key + char *key; + //Object upload id + char *upload_id; + + int setting_flag; +} qs_uploads_t; + +typedef struct +{ + + qs_list_t node; + + qs_uploads_t *content; + +} qs_uploads_item_t; + +// uploads init function. +void init_uploads(qs_uploads_t * input); + +// uploads release function. +void release_uploads(qs_uploads_t * output); + +#ifdef __cplusplus +}; +#endif diff --git a/include/types/ACLType.h b/include/types/ACLType.h new file mode 100644 index 0000000..f71eea1 --- /dev/null +++ b/include/types/ACLType.h @@ -0,0 +1,86 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "../QsBaseType.h" +#include + +// Headers of CustomizedType. +#include "GranteeType.h" + +#ifdef BUILD_C_STYLE_INTERFACE +#include "../service_with_c_style/types/ACLType.h" +#endif // BUILD_C_STYLE_INTERFACE + +#define SETTING_ACL_GRANTEE_FLAG 0x1 + +// Permission for this grantee'flag +// Permission's available values: READ, WRITE, FULL_CONTROL +#define SETTING_ACL_PERMISSION_FLAG 0x2 + +//ACLType presents costom type:ACL. +class QS_SDK_API ACLType:QsBaseType +{ + +public: + ACLType() + { + }; + ACLType(std::string serializedStr); + +#ifdef BUILD_C_STYLE_INTERFACE + ACLType(qs_acl_t acl); + qs_acl_t *toCStyleObj(); +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetGrantee(GranteeType Grantee) + { + m_settingFlag |= SETTING_ACL_GRANTEE_FLAG; + m_Grantee = Grantee; + }; + + inline GranteeType GetGrantee() + { + return m_Grantee; + }; + + // Permission for this grantee + // Permission's available values: READ, WRITE, FULL_CONTROL + + inline void SetPermission(std::string Permission) + { + m_settingFlag |= SETTING_ACL_PERMISSION_FLAG; + m_Permission = Permission; + }; + + inline std::string GetPermission() + { + return m_Permission; + }; + + std::string Serialize(); + +private: + + GranteeType m_Grantee; // Required + + // Permission for this grantee + // Permission's available values: READ, WRITE, FULL_CONTROL + std::string m_Permission; // Required + + int setting_flag; +}; diff --git a/include/types/BucketType.h b/include/types/BucketType.h new file mode 100644 index 0000000..aee780e --- /dev/null +++ b/include/types/BucketType.h @@ -0,0 +1,122 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "../QsBaseType.h" +#include + +// Headers of CustomizedType. + +#ifdef BUILD_C_STYLE_INTERFACE +#include "../service_with_c_style/types/BucketType.h" +#endif // BUILD_C_STYLE_INTERFACE + +// Created time of the bucket'flag +#define SETTING_BUCKET_CREATED_FLAG 0x1 + +// QingCloud Zone ID'flag +#define SETTING_BUCKET_LOCATION_FLAG 0x2 + +// Bucket name'flag +#define SETTING_BUCKET_NAME_FLAG 0x4 + +// URL to access the bucket'flag +#define SETTING_BUCKET_URL_FLAG 0x8 + +//BucketType presents costom type:Bucket. +class QS_SDK_API BucketType:QsBaseType +{ + +public: + BucketType() + { + }; + BucketType(std::string serializedStr); + +#ifdef BUILD_C_STYLE_INTERFACE + BucketType(qs_bucket_t bucket); + qs_bucket_t *toCStyleObj(); +#endif // BUILD_C_STYLE_INTERFACE// Created time of the bucket + + inline void SetCreated(std::string Created) + { + m_settingFlag |= SETTING_BUCKET_CREATED_FLAG; + m_Created = Created; + }; + + inline std::string GetCreated() + { + return m_Created; + }; + + // QingCloud Zone ID + + inline void SetLocation(std::string Location) + { + m_settingFlag |= SETTING_BUCKET_LOCATION_FLAG; + m_Location = Location; + }; + + inline std::string GetLocation() + { + return m_Location; + }; + + // Bucket name + + inline void SetName(std::string Name) + { + m_settingFlag |= SETTING_BUCKET_NAME_FLAG; + m_Name = Name; + }; + + inline std::string GetName() + { + return m_Name; + }; + + // URL to access the bucket + + inline void SetURL(std::string URL) + { + m_settingFlag |= SETTING_BUCKET_URL_FLAG; + m_URL = URL; + }; + + inline std::string GetURL() + { + return m_URL; + }; + + std::string Serialize(); + +private: + + // Created time of the bucket + std::string m_Created; + + // QingCloud Zone ID + std::string m_Location; + + // Bucket name + std::string m_Name; + + // URL to access the bucket + std::string m_URL; + + int setting_flag; +}; diff --git a/include/types/CORSRuleType.h b/include/types/CORSRuleType.h new file mode 100644 index 0000000..94b03a0 --- /dev/null +++ b/include/types/CORSRuleType.h @@ -0,0 +1,177 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "../QsBaseType.h" +#include + +// Headers of CustomizedType. + +#ifdef BUILD_C_STYLE_INTERFACE +#include "../service_with_c_style/types/CORSRuleType.h" +#endif // BUILD_C_STYLE_INTERFACE + +// Allowed origin'flag +#define SETTING_CORS_RULE_ALLOWED_ORIGIN_FLAG 0x1 + +// Expose headers'flag +#define SETTING_CORS_RULE_EXPOSE_HEADERS_FLAG 0x2 + +// Max age seconds'flag +#define SETTING_CORS_RULE_MAX_AGE_SECONDS_FLAG 0x4 + +// Allowed headers'flag +#define SETTING_CORS_RULE_ALLOWED_HEADERS_FLAG 0x8 + +// Allowed methods'flag +#define SETTING_CORS_RULE_ALLOWED_METHODS_FLAG 0x10 + +//CORSRuleType presents costom type:CORSRule. +class QS_SDK_API CORSRuleType:QsBaseType +{ + +public: + CORSRuleType() + { + }; + CORSRuleType(std::string serializedStr); + +#ifdef BUILD_C_STYLE_INTERFACE + CORSRuleType(qs_cors_rule_t cors_rule); + qs_cors_rule_t *toCStyleObj(); +#endif // BUILD_C_STYLE_INTERFACE// Allowed headers +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetAllowedHeaders(qs_list_t * allowed_headers) + { + m_settingFlag |= SETTING_CORS_RULE_ALLOWED_HEADERS_FLAG; + qs_string_item_t *item; + qs_list_for_each_entry(qs_string_item_t, item, allowed_headers) + { + m_AllowedHeaders.push_back(item->content); + } + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetAllowedHeaders(std::vector < std::string > AllowedHeaders) + { + m_settingFlag |= SETTING_CORS_RULE_ALLOWED_HEADERS_FLAG; + m_AllowedHeaders = AllowedHeaders; + }; + + inline std::vector < std::string > GetAllowedHeaders() + { + return m_AllowedHeaders; + }; + + // Allowed methods +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetAllowedMethods(qs_list_t * allowed_methods) + { + m_settingFlag |= SETTING_CORS_RULE_ALLOWED_METHODS_FLAG; + qs_string_item_t *item; + qs_list_for_each_entry(qs_string_item_t, item, allowed_methods) + { + m_AllowedMethods.push_back(item->content); + } + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetAllowedMethods(std::vector < std::string > AllowedMethods) + { + m_settingFlag |= SETTING_CORS_RULE_ALLOWED_METHODS_FLAG; + m_AllowedMethods = AllowedMethods; + }; + + inline std::vector < std::string > GetAllowedMethods() + { + return m_AllowedMethods; + }; + + // Allowed origin + + inline void SetAllowedOrigin(std::string AllowedOrigin) + { + m_settingFlag |= SETTING_CORS_RULE_ALLOWED_ORIGIN_FLAG; + m_AllowedOrigin = AllowedOrigin; + }; + + inline std::string GetAllowedOrigin() + { + return m_AllowedOrigin; + }; + + // Expose headers +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetExposeHeaders(qs_list_t * expose_headers) + { + m_settingFlag |= SETTING_CORS_RULE_EXPOSE_HEADERS_FLAG; + qs_string_item_t *item; + qs_list_for_each_entry(qs_string_item_t, item, expose_headers) + { + m_ExposeHeaders.push_back(item->content); + } + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetExposeHeaders(std::vector < std::string > ExposeHeaders) + { + m_settingFlag |= SETTING_CORS_RULE_EXPOSE_HEADERS_FLAG; + m_ExposeHeaders = ExposeHeaders; + }; + + inline std::vector < std::string > GetExposeHeaders() + { + return m_ExposeHeaders; + }; + + // Max age seconds + + inline void SetMaxAgeSeconds(int MaxAgeSeconds) + { + m_settingFlag |= SETTING_CORS_RULE_MAX_AGE_SECONDS_FLAG; + m_MaxAgeSeconds = MaxAgeSeconds; + }; + + inline int GetMaxAgeSeconds() + { + return m_MaxAgeSeconds; + }; + + std::string Serialize(); + +private: + + // Allowed headers + + std::vector < std::string > m_AllowedHeaders; + + // Allowed methods + + std::vector < std::string > m_AllowedMethods; // Required + + // Allowed origin + std::string m_AllowedOrigin; // Required + + // Expose headers + + std::vector < std::string > m_ExposeHeaders; + + // Max age seconds + int m_MaxAgeSeconds; + + int setting_flag; +}; diff --git a/include/types/ConditionType.h b/include/types/ConditionType.h new file mode 100644 index 0000000..f6d9b54 --- /dev/null +++ b/include/types/ConditionType.h @@ -0,0 +1,128 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "../QsBaseType.h" +#include + +// Headers of CustomizedType. +#include "IPAddressType.h" +#include "IsNullType.h" +#include "NotIPAddressType.h" +#include "StringLikeType.h" +#include "StringNotLikeType.h" + +#ifdef BUILD_C_STYLE_INTERFACE +#include "../service_with_c_style/types/ConditionType.h" +#endif // BUILD_C_STYLE_INTERFACE + +#define SETTING_CONDITION_IP_ADDRESS_FLAG 0x1 + +#define SETTING_CONDITION_IS_NULL_FLAG 0x2 + +#define SETTING_CONDITION_NOT_IP_ADDRESS_FLAG 0x4 + +#define SETTING_CONDITION_STRING_LIKE_FLAG 0x8 + +#define SETTING_CONDITION_STRING_NOT_LIKE_FLAG 0x10 + +//ConditionType presents costom type:Condition. +class QS_SDK_API ConditionType:QsBaseType +{ + +public: + ConditionType() + { + }; + ConditionType(std::string serializedStr); + +#ifdef BUILD_C_STYLE_INTERFACE + ConditionType(qs_condition_t condition); + qs_condition_t *toCStyleObj(); +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetIPAddress(IPAddressType IPAddress) + { + m_settingFlag |= SETTING_CONDITION_IP_ADDRESS_FLAG; + m_IPAddress = IPAddress; + }; + + inline IPAddressType GetIPAddress() + { + return m_IPAddress; + }; + + inline void SetIsNull(IsNullType IsNull) + { + m_settingFlag |= SETTING_CONDITION_IS_NULL_FLAG; + m_IsNull = IsNull; + }; + + inline IsNullType GetIsNull() + { + return m_IsNull; + }; + + inline void SetNotIPAddress(NotIPAddressType NotIPAddress) + { + m_settingFlag |= SETTING_CONDITION_NOT_IP_ADDRESS_FLAG; + m_NotIPAddress = NotIPAddress; + }; + + inline NotIPAddressType GetNotIPAddress() + { + return m_NotIPAddress; + }; + + inline void SetStringLike(StringLikeType StringLike) + { + m_settingFlag |= SETTING_CONDITION_STRING_LIKE_FLAG; + m_StringLike = StringLike; + }; + + inline StringLikeType GetStringLike() + { + return m_StringLike; + }; + + inline void SetStringNotLike(StringNotLikeType StringNotLike) + { + m_settingFlag |= SETTING_CONDITION_STRING_NOT_LIKE_FLAG; + m_StringNotLike = StringNotLike; + }; + + inline StringNotLikeType GetStringNotLike() + { + return m_StringNotLike; + }; + + std::string Serialize(); + +private: + + IPAddressType m_IPAddress; + + IsNullType m_IsNull; + + NotIPAddressType m_NotIPAddress; + + StringLikeType m_StringLike; + + StringNotLikeType m_StringNotLike; + + int setting_flag; +}; diff --git a/include/types/GranteeType.h b/include/types/GranteeType.h new file mode 100644 index 0000000..d7d7690 --- /dev/null +++ b/include/types/GranteeType.h @@ -0,0 +1,106 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "../QsBaseType.h" +#include + +// Headers of CustomizedType. + +#ifdef BUILD_C_STYLE_INTERFACE +#include "../service_with_c_style/types/GranteeType.h" +#endif // BUILD_C_STYLE_INTERFACE + +// Grantee user ID'flag +#define SETTING_GRANTEE_ID_FLAG 0x1 + +// Grantee group name'flag +#define SETTING_GRANTEE_NAME_FLAG 0x2 + +// Grantee type'flag +// Type's available values: user, group +#define SETTING_GRANTEE_TYPE_FLAG 0x4 + +//GranteeType presents costom type:Grantee. +class QS_SDK_API GranteeType:QsBaseType +{ + +public: + GranteeType() + { + }; + GranteeType(std::string serializedStr); + +#ifdef BUILD_C_STYLE_INTERFACE + GranteeType(qs_grantee_t grantee); + qs_grantee_t *toCStyleObj(); +#endif // BUILD_C_STYLE_INTERFACE// Grantee user ID + + inline void SetID(std::string ID) + { + m_settingFlag |= SETTING_GRANTEE_ID_FLAG; + m_ID = ID; + }; + + inline std::string GetID() + { + return m_ID; + }; + + // Grantee group name + + inline void SetName(std::string Name) + { + m_settingFlag |= SETTING_GRANTEE_NAME_FLAG; + m_Name = Name; + }; + + inline std::string GetName() + { + return m_Name; + }; + + // Grantee type + // Type's available values: user, group + + inline void SetType(std::string Type) + { + m_settingFlag |= SETTING_GRANTEE_TYPE_FLAG; + m_Type = Type; + }; + + inline std::string GetType() + { + return m_Type; + }; + + std::string Serialize(); + +private: + + // Grantee user ID + std::string m_ID; + + // Grantee group name + std::string m_Name; + + // Grantee type + // Type's available values: user, group + std::string m_Type; // Required + + int setting_flag; +}; diff --git a/include/types/IPAddressType.h b/include/types/IPAddressType.h new file mode 100644 index 0000000..44e872a --- /dev/null +++ b/include/types/IPAddressType.h @@ -0,0 +1,77 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "../QsBaseType.h" +#include + +// Headers of CustomizedType. + +#ifdef BUILD_C_STYLE_INTERFACE +#include "../service_with_c_style/types/IPAddressType.h" +#endif // BUILD_C_STYLE_INTERFACE + +// Source IP'flag +#define SETTING_IP_ADDRESS_SOURCE_IP_FLAG 0x1 + +//IPAddressType presents costom type:IPAddress. +class QS_SDK_API IPAddressType:QsBaseType +{ + +public: + IPAddressType() + { + }; + IPAddressType(std::string serializedStr); + +#ifdef BUILD_C_STYLE_INTERFACE + IPAddressType(qs_ip_address_t ip_address); + qs_ip_address_t *toCStyleObj(); +#endif // BUILD_C_STYLE_INTERFACE// Source IP +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetSourceIP(qs_list_t * source_ip) + { + m_settingFlag |= SETTING_IP_ADDRESS_SOURCE_IP_FLAG; + qs_string_item_t *item; + qs_list_for_each_entry(qs_string_item_t, item, source_ip) + { + m_SourceIP.push_back(item->content); + } + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetSourceIP(std::vector < std::string > SourceIP) + { + m_settingFlag |= SETTING_IP_ADDRESS_SOURCE_IP_FLAG; + m_SourceIP = SourceIP; + }; + + inline std::vector < std::string > GetSourceIP() + { + return m_SourceIP; + }; + + std::string Serialize(); + +private: + + // Source IP + + std::vector < std::string > m_SourceIP; + + int setting_flag; +}; diff --git a/include/types/IsNullType.h b/include/types/IsNullType.h new file mode 100644 index 0000000..f022850 --- /dev/null +++ b/include/types/IsNullType.h @@ -0,0 +1,65 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "../QsBaseType.h" +#include + +// Headers of CustomizedType. + +#ifdef BUILD_C_STYLE_INTERFACE +#include "../service_with_c_style/types/IsNullType.h" +#endif // BUILD_C_STYLE_INTERFACE + +// Refer url'flag +#define SETTING_IS_NULL_REFERER_FLAG 0x1 + +//IsNullType presents costom type:IsNull. +class QS_SDK_API IsNullType:QsBaseType +{ + +public: + IsNullType() + { + }; + IsNullType(std::string serializedStr); + +#ifdef BUILD_C_STYLE_INTERFACE + IsNullType(qs_is_null_t is_null); + qs_is_null_t *toCStyleObj(); +#endif // BUILD_C_STYLE_INTERFACE// Refer url + + inline void SetReferer(bool Referer) + { + m_settingFlag |= SETTING_IS_NULL_REFERER_FLAG; + m_Referer = Referer; + }; + + inline bool GetReferer() + { + return m_Referer; + }; + + std::string Serialize(); + +private: + + // Refer url + bool m_Referer; + + int setting_flag; +}; diff --git a/include/types/KeyDeleteErrorType.h b/include/types/KeyDeleteErrorType.h new file mode 100644 index 0000000..bc68a97 --- /dev/null +++ b/include/types/KeyDeleteErrorType.h @@ -0,0 +1,104 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "../QsBaseType.h" +#include + +// Headers of CustomizedType. +#include "KeyType.h" + +#ifdef BUILD_C_STYLE_INTERFACE +#include "../service_with_c_style/types/KeyDeleteErrorType.h" +#endif // BUILD_C_STYLE_INTERFACE + +// Object key'flag +#define SETTING_KEY_DELETE_ERROR_KEY_FLAG 0x1 + +// Error message'flag +#define SETTING_KEY_DELETE_ERROR_MESSAGE_FLAG 0x2 + +// Error code'flag +#define SETTING_KEY_DELETE_ERROR_CODE_FLAG 0x4 + +//KeyDeleteErrorType presents costom type:KeyDeleteError. +class QS_SDK_API KeyDeleteErrorType:QsBaseType +{ + +public: + KeyDeleteErrorType() + { + }; + KeyDeleteErrorType(std::string serializedStr); + +#ifdef BUILD_C_STYLE_INTERFACE + KeyDeleteErrorType(qs_key_delete_error_t key_delete_error); + qs_key_delete_error_t *toCStyleObj(); +#endif // BUILD_C_STYLE_INTERFACE// Error code + + inline void SetCode(std::string Code) + { + m_settingFlag |= SETTING_KEY_DELETE_ERROR_CODE_FLAG; + m_Code = Code; + }; + + inline std::string GetCode() + { + return m_Code; + }; + + // Object key + + inline void SetKey(std::string Key) + { + m_settingFlag |= SETTING_KEY_DELETE_ERROR_KEY_FLAG; + m_Key = Key; + }; + + inline std::string GetKey() + { + return m_Key; + }; + + // Error message + + inline void SetMessage(std::string Message) + { + m_settingFlag |= SETTING_KEY_DELETE_ERROR_MESSAGE_FLAG; + m_Message = Message; + }; + + inline std::string GetMessage() + { + return m_Message; + }; + + std::string Serialize(); + +private: + + // Error code + std::string m_Code; + + // Object key + std::string m_Key; + + // Error message + std::string m_Message; + + int setting_flag; +}; diff --git a/include/types/KeyType.h b/include/types/KeyType.h new file mode 100644 index 0000000..6eefd14 --- /dev/null +++ b/include/types/KeyType.h @@ -0,0 +1,180 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "../QsBaseType.h" +#include + +// Headers of CustomizedType. +#include "KeyType.h" + +#ifdef BUILD_C_STYLE_INTERFACE +#include "../service_with_c_style/types/KeyType.h" +#endif // BUILD_C_STYLE_INTERFACE + +// Object key'flag +#define SETTING_KEY_KEY_FLAG 0x1 + +// MIME type of the object'flag +#define SETTING_KEY_MIME_TYPE_FLAG 0x2 + +// Last modified time in unix time format'flag +#define SETTING_KEY_MODIFIED_FLAG 0x4 + +// Object content size'flag +#define SETTING_KEY_SIZE_FLAG 0x8 + +// Object created time'flag +#define SETTING_KEY_CREATED_FLAG 0x10 + +// Whether this key is encrypted'flag +#define SETTING_KEY_ENCRYPTED_FLAG 0x20 + +// MD5sum of the object'flag +#define SETTING_KEY_ETAG_FLAG 0x40 + +//KeyType presents costom type:Key. +class QS_SDK_API KeyType:QsBaseType +{ + +public: + KeyType() + { + }; + KeyType(std::string serializedStr); + +#ifdef BUILD_C_STYLE_INTERFACE + KeyType(qs_key_t key); + qs_key_t *toCStyleObj(); +#endif // BUILD_C_STYLE_INTERFACE// Object created time + + inline void SetCreated(std::string Created) + { + m_settingFlag |= SETTING_KEY_CREATED_FLAG; + m_Created = Created; + }; + + inline std::string GetCreated() + { + return m_Created; + }; + + // Whether this key is encrypted + + inline void SetEncrypted(bool Encrypted) + { + m_settingFlag |= SETTING_KEY_ENCRYPTED_FLAG; + m_Encrypted = Encrypted; + }; + + inline bool GetEncrypted() + { + return m_Encrypted; + }; + + // MD5sum of the object + + inline void SetEtag(std::string Etag) + { + m_settingFlag |= SETTING_KEY_ETAG_FLAG; + m_Etag = Etag; + }; + + inline std::string GetEtag() + { + return m_Etag; + }; + + // Object key + + inline void SetKey(std::string Key) + { + m_settingFlag |= SETTING_KEY_KEY_FLAG; + m_Key = Key; + }; + + inline std::string GetKey() + { + return m_Key; + }; + + // MIME type of the object + + inline void SetMimeType(std::string MimeType) + { + m_settingFlag |= SETTING_KEY_MIME_TYPE_FLAG; + m_MimeType = MimeType; + }; + + inline std::string GetMimeType() + { + return m_MimeType; + }; + + // Last modified time in unix time format + + inline void SetModified(int Modified) + { + m_settingFlag |= SETTING_KEY_MODIFIED_FLAG; + m_Modified = Modified; + }; + + inline int GetModified() + { + return m_Modified; + }; + + // Object content size + + inline void SetSize(int64_t Size) + { + m_settingFlag |= SETTING_KEY_SIZE_FLAG; + m_Size = Size; + }; + + inline int64_t GetSize() + { + return m_Size; + }; + + std::string Serialize(); + +private: + + // Object created time + std::string m_Created; + + // Whether this key is encrypted + bool m_Encrypted; + + // MD5sum of the object + std::string m_Etag; + + // Object key + std::string m_Key; + + // MIME type of the object + std::string m_MimeType; + + // Last modified time in unix time format + int m_Modified; + + // Object content size + int64_t m_Size; + + int setting_flag; +}; diff --git a/include/types/NotIPAddressType.h b/include/types/NotIPAddressType.h new file mode 100644 index 0000000..2248882 --- /dev/null +++ b/include/types/NotIPAddressType.h @@ -0,0 +1,77 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "../QsBaseType.h" +#include + +// Headers of CustomizedType. + +#ifdef BUILD_C_STYLE_INTERFACE +#include "../service_with_c_style/types/NotIPAddressType.h" +#endif // BUILD_C_STYLE_INTERFACE + +// Source IP'flag +#define SETTING_NOT_IP_ADDRESS_SOURCE_IP_FLAG 0x1 + +//NotIPAddressType presents costom type:NotIPAddress. +class QS_SDK_API NotIPAddressType:QsBaseType +{ + +public: + NotIPAddressType() + { + }; + NotIPAddressType(std::string serializedStr); + +#ifdef BUILD_C_STYLE_INTERFACE + NotIPAddressType(qs_not_ip_address_t not_ip_address); + qs_not_ip_address_t *toCStyleObj(); +#endif // BUILD_C_STYLE_INTERFACE// Source IP +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetSourceIP(qs_list_t * source_ip) + { + m_settingFlag |= SETTING_NOT_IP_ADDRESS_SOURCE_IP_FLAG; + qs_string_item_t *item; + qs_list_for_each_entry(qs_string_item_t, item, source_ip) + { + m_SourceIP.push_back(item->content); + } + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetSourceIP(std::vector < std::string > SourceIP) + { + m_settingFlag |= SETTING_NOT_IP_ADDRESS_SOURCE_IP_FLAG; + m_SourceIP = SourceIP; + }; + + inline std::vector < std::string > GetSourceIP() + { + return m_SourceIP; + }; + + std::string Serialize(); + +private: + + // Source IP + + std::vector < std::string > m_SourceIP; + + int setting_flag; +}; diff --git a/include/types/ObjectPartType.h b/include/types/ObjectPartType.h new file mode 100644 index 0000000..3797670 --- /dev/null +++ b/include/types/ObjectPartType.h @@ -0,0 +1,122 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "../QsBaseType.h" +#include + +// Headers of CustomizedType. + +#ifdef BUILD_C_STYLE_INTERFACE +#include "../service_with_c_style/types/ObjectPartType.h" +#endif // BUILD_C_STYLE_INTERFACE + +// Object part size'flag +#define SETTING_OBJECT_PART_SIZE_FLAG 0x1 + +// Object part created time'flag +#define SETTING_OBJECT_PART_CREATED_FLAG 0x2 + +// MD5sum of the object part'flag +#define SETTING_OBJECT_PART_ETAG_FLAG 0x4 + +// Object part number'flag +#define SETTING_OBJECT_PART_PART_NUMBER_FLAG 0x8 + +//ObjectPartType presents costom type:ObjectPart. +class QS_SDK_API ObjectPartType:QsBaseType +{ + +public: + ObjectPartType() + { + }; + ObjectPartType(std::string serializedStr); + +#ifdef BUILD_C_STYLE_INTERFACE + ObjectPartType(qs_object_part_t object_part); + qs_object_part_t *toCStyleObj(); +#endif // BUILD_C_STYLE_INTERFACE// Object part created time + + inline void SetCreated(std::string Created) + { + m_settingFlag |= SETTING_OBJECT_PART_CREATED_FLAG; + m_Created = Created; + }; + + inline std::string GetCreated() + { + return m_Created; + }; + + // MD5sum of the object part + + inline void SetEtag(std::string Etag) + { + m_settingFlag |= SETTING_OBJECT_PART_ETAG_FLAG; + m_Etag = Etag; + }; + + inline std::string GetEtag() + { + return m_Etag; + }; + + // Object part number + + inline void SetPartNumber(int PartNumber) + { + m_settingFlag |= SETTING_OBJECT_PART_PART_NUMBER_FLAG; + m_PartNumber = PartNumber; + }; + + inline int GetPartNumber() + { + return m_PartNumber; + }; + + // Object part size + + inline void SetSize(int64_t Size) + { + m_settingFlag |= SETTING_OBJECT_PART_SIZE_FLAG; + m_Size = Size; + }; + + inline int64_t GetSize() + { + return m_Size; + }; + + std::string Serialize(); + +private: + + // Object part created time + std::string m_Created; + + // MD5sum of the object part + std::string m_Etag; + + // Object part number + int m_PartNumber; // Required + + // Object part size + int64_t m_Size; + + int setting_flag; +}; diff --git a/include/types/OwnerType.h b/include/types/OwnerType.h new file mode 100644 index 0000000..1156c59 --- /dev/null +++ b/include/types/OwnerType.h @@ -0,0 +1,84 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "../QsBaseType.h" +#include + +// Headers of CustomizedType. + +#ifdef BUILD_C_STYLE_INTERFACE +#include "../service_with_c_style/types/OwnerType.h" +#endif // BUILD_C_STYLE_INTERFACE + +// User ID'flag +#define SETTING_OWNER_ID_FLAG 0x1 + +// Username'flag +#define SETTING_OWNER_NAME_FLAG 0x2 + +//OwnerType presents costom type:Owner. +class QS_SDK_API OwnerType:QsBaseType +{ + +public: + OwnerType() + { + }; + OwnerType(std::string serializedStr); + +#ifdef BUILD_C_STYLE_INTERFACE + OwnerType(qs_owner_t owner); + qs_owner_t *toCStyleObj(); +#endif // BUILD_C_STYLE_INTERFACE// User ID + + inline void SetID(std::string ID) + { + m_settingFlag |= SETTING_OWNER_ID_FLAG; + m_ID = ID; + }; + + inline std::string GetID() + { + return m_ID; + }; + + // Username + + inline void SetName(std::string Name) + { + m_settingFlag |= SETTING_OWNER_NAME_FLAG; + m_Name = Name; + }; + + inline std::string GetName() + { + return m_Name; + }; + + std::string Serialize(); + +private: + + // User ID + std::string m_ID; + + // Username + std::string m_Name; + + int setting_flag; +}; diff --git a/include/types/StatementType.h b/include/types/StatementType.h new file mode 100644 index 0000000..2b9812e --- /dev/null +++ b/include/types/StatementType.h @@ -0,0 +1,196 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "../QsBaseType.h" +#include + +// Headers of CustomizedType. +#include "ConditionType.h" + +#ifdef BUILD_C_STYLE_INTERFACE +#include "../service_with_c_style/types/StatementType.h" +#endif // BUILD_C_STYLE_INTERFACE + +// Bucket policy id, must be unique'flag +#define SETTING_STATEMENT_ID_FLAG 0x1 + +// The resources to apply bucket policy'flag +#define SETTING_STATEMENT_RESOURCE_FLAG 0x2 + +// The user to apply bucket policy'flag +#define SETTING_STATEMENT_USER_FLAG 0x4 + +// QingStor API methods'flag +#define SETTING_STATEMENT_ACTION_FLAG 0x8 + +#define SETTING_STATEMENT_CONDITION_FLAG 0x10 + +// Statement effect'flag +// Effect's available values: allow, deny +#define SETTING_STATEMENT_EFFECT_FLAG 0x20 + +//StatementType presents costom type:Statement. +class QS_SDK_API StatementType:QsBaseType +{ + +public: + StatementType() + { + }; + StatementType(std::string serializedStr); + +#ifdef BUILD_C_STYLE_INTERFACE + StatementType(qs_statement_t statement); + qs_statement_t *toCStyleObj(); +#endif // BUILD_C_STYLE_INTERFACE// QingStor API methods +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetAction(qs_list_t * action) + { + m_settingFlag |= SETTING_STATEMENT_ACTION_FLAG; + qs_string_item_t *item; + qs_list_for_each_entry(qs_string_item_t, item, action) + { + m_Action.push_back(item->content); + } + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetAction(std::vector < std::string > Action) + { + m_settingFlag |= SETTING_STATEMENT_ACTION_FLAG; + m_Action = Action; + }; + + inline std::vector < std::string > GetAction() + { + return m_Action; + }; + + inline void SetCondition(ConditionType Condition) + { + m_settingFlag |= SETTING_STATEMENT_CONDITION_FLAG; + m_Condition = Condition; + }; + + inline ConditionType GetCondition() + { + return m_Condition; + }; + + // Statement effect + // Effect's available values: allow, deny + + inline void SetEffect(std::string Effect) + { + m_settingFlag |= SETTING_STATEMENT_EFFECT_FLAG; + m_Effect = Effect; + }; + + inline std::string GetEffect() + { + return m_Effect; + }; + + // Bucket policy id, must be unique + + inline void SetID(std::string ID) + { + m_settingFlag |= SETTING_STATEMENT_ID_FLAG; + m_ID = ID; + }; + + inline std::string GetID() + { + return m_ID; + }; + + // The resources to apply bucket policy +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetResource(qs_list_t * resource) + { + m_settingFlag |= SETTING_STATEMENT_RESOURCE_FLAG; + qs_string_item_t *item; + qs_list_for_each_entry(qs_string_item_t, item, resource) + { + m_Resource.push_back(item->content); + } + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetResource(std::vector < std::string > Resource) + { + m_settingFlag |= SETTING_STATEMENT_RESOURCE_FLAG; + m_Resource = Resource; + }; + + inline std::vector < std::string > GetResource() + { + return m_Resource; + }; + + // The user to apply bucket policy +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetUser(qs_list_t * user) + { + m_settingFlag |= SETTING_STATEMENT_USER_FLAG; + qs_string_item_t *item; + qs_list_for_each_entry(qs_string_item_t, item, user) + { + m_User.push_back(item->content); + } + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetUser(std::vector < std::string > User) + { + m_settingFlag |= SETTING_STATEMENT_USER_FLAG; + m_User = User; + }; + + inline std::vector < std::string > GetUser() + { + return m_User; + }; + + std::string Serialize(); + +private: + + // QingStor API methods + + std::vector < std::string > m_Action; // Required + + ConditionType m_Condition; + + // Statement effect + // Effect's available values: allow, deny + std::string m_Effect; // Required + + // Bucket policy id, must be unique + std::string m_ID; // Required + + // The resources to apply bucket policy + + std::vector < std::string > m_Resource; + + // The user to apply bucket policy + + std::vector < std::string > m_User; // Required + + int setting_flag; +}; diff --git a/include/types/StringLikeType.h b/include/types/StringLikeType.h new file mode 100644 index 0000000..dab1be6 --- /dev/null +++ b/include/types/StringLikeType.h @@ -0,0 +1,77 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "../QsBaseType.h" +#include + +// Headers of CustomizedType. + +#ifdef BUILD_C_STYLE_INTERFACE +#include "../service_with_c_style/types/StringLikeType.h" +#endif // BUILD_C_STYLE_INTERFACE + +// Refer url'flag +#define SETTING_STRING_LIKE_REFERER_FLAG 0x1 + +//StringLikeType presents costom type:StringLike. +class QS_SDK_API StringLikeType:QsBaseType +{ + +public: + StringLikeType() + { + }; + StringLikeType(std::string serializedStr); + +#ifdef BUILD_C_STYLE_INTERFACE + StringLikeType(qs_string_like_t string_like); + qs_string_like_t *toCStyleObj(); +#endif // BUILD_C_STYLE_INTERFACE// Refer url +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetReferer(qs_list_t * referer) + { + m_settingFlag |= SETTING_STRING_LIKE_REFERER_FLAG; + qs_string_item_t *item; + qs_list_for_each_entry(qs_string_item_t, item, referer) + { + m_Referer.push_back(item->content); + } + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetReferer(std::vector < std::string > Referer) + { + m_settingFlag |= SETTING_STRING_LIKE_REFERER_FLAG; + m_Referer = Referer; + }; + + inline std::vector < std::string > GetReferer() + { + return m_Referer; + }; + + std::string Serialize(); + +private: + + // Refer url + + std::vector < std::string > m_Referer; + + int setting_flag; +}; diff --git a/include/types/StringNotLikeType.h b/include/types/StringNotLikeType.h new file mode 100644 index 0000000..4b7c0db --- /dev/null +++ b/include/types/StringNotLikeType.h @@ -0,0 +1,77 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "../QsBaseType.h" +#include + +// Headers of CustomizedType. + +#ifdef BUILD_C_STYLE_INTERFACE +#include "../service_with_c_style/types/StringNotLikeType.h" +#endif // BUILD_C_STYLE_INTERFACE + +// Refer url'flag +#define SETTING_STRING_NOT_LIKE_REFERER_FLAG 0x1 + +//StringNotLikeType presents costom type:StringNotLike. +class QS_SDK_API StringNotLikeType:QsBaseType +{ + +public: + StringNotLikeType() + { + }; + StringNotLikeType(std::string serializedStr); + +#ifdef BUILD_C_STYLE_INTERFACE + StringNotLikeType(qs_string_not_like_t string_not_like); + qs_string_not_like_t *toCStyleObj(); +#endif // BUILD_C_STYLE_INTERFACE// Refer url +#ifdef BUILD_C_STYLE_INTERFACE + inline void SetReferer(qs_list_t * referer) + { + m_settingFlag |= SETTING_STRING_NOT_LIKE_REFERER_FLAG; + qs_string_item_t *item; + qs_list_for_each_entry(qs_string_item_t, item, referer) + { + m_Referer.push_back(item->content); + } + }; +#endif // BUILD_C_STYLE_INTERFACE + + inline void SetReferer(std::vector < std::string > Referer) + { + m_settingFlag |= SETTING_STRING_NOT_LIKE_REFERER_FLAG; + m_Referer = Referer; + }; + + inline std::vector < std::string > GetReferer() + { + return m_Referer; + }; + + std::string Serialize(); + +private: + + // Refer url + + std::vector < std::string > m_Referer; + + int setting_flag; +}; diff --git a/include/types/UploadsType.h b/include/types/UploadsType.h new file mode 100644 index 0000000..e09db41 --- /dev/null +++ b/include/types/UploadsType.h @@ -0,0 +1,104 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "../QsBaseType.h" +#include + +// Headers of CustomizedType. +#include "KeyType.h" + +#ifdef BUILD_C_STYLE_INTERFACE +#include "../service_with_c_style/types/UploadsType.h" +#endif // BUILD_C_STYLE_INTERFACE + +// Object part created time'flag +#define SETTING_UPLOADS_CREATED_FLAG 0x1 + +// Object key'flag +#define SETTING_UPLOADS_KEY_FLAG 0x2 + +// Object upload id'flag +#define SETTING_UPLOADS_UPLOAD_ID_FLAG 0x4 + +//UploadsType presents costom type:Uploads. +class QS_SDK_API UploadsType:QsBaseType +{ + +public: + UploadsType() + { + }; + UploadsType(std::string serializedStr); + +#ifdef BUILD_C_STYLE_INTERFACE + UploadsType(qs_uploads_t uploads); + qs_uploads_t *toCStyleObj(); +#endif // BUILD_C_STYLE_INTERFACE// Object part created time + + inline void SetCreated(std::string Created) + { + m_settingFlag |= SETTING_UPLOADS_CREATED_FLAG; + m_Created = Created; + }; + + inline std::string GetCreated() + { + return m_Created; + }; + + // Object key + + inline void SetKey(std::string Key) + { + m_settingFlag |= SETTING_UPLOADS_KEY_FLAG; + m_Key = Key; + }; + + inline std::string GetKey() + { + return m_Key; + }; + + // Object upload id + + inline void SetUploadID(std::string UploadID) + { + m_settingFlag |= SETTING_UPLOADS_UPLOAD_ID_FLAG; + m_UploadID = UploadID; + }; + + inline std::string GetUploadID() + { + return m_UploadID; + }; + + std::string Serialize(); + +private: + + // Object part created time + std::string m_Created; + + // Object key + std::string m_Key; + + // Object upload id + std::string m_UploadID; + + int setting_flag; +}; diff --git a/samples/samples_sdk_c/CMakeLists.txt b/samples/samples_sdk_c/CMakeLists.txt new file mode 100644 index 0000000..f6b03c2 --- /dev/null +++ b/samples/samples_sdk_c/CMakeLists.txt @@ -0,0 +1,31 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +PROJECT(Sample_sdk_c) + +SET(CMAKE_BUILD_TYPE "Debug") +IF(WIN32) +ELSE() +SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CFLAGS} -O0 -Wall -g2 -ggdb -L /lib64 -l pthread") +SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CFLAGS} -O3 -Wall") +ENDIF() + +GET_FILENAME_COMPONENT(COMPILER_DIR ${CMAKE_CXX_COMPILER} DIRECTORY) +GET_FILENAME_COMPONENT(VC_DIR ${COMPILER_DIR} DIRECTORY) + +SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" $ {CMAKE_MODULE_PATH}) +SET(SRC_LIST main.c) + +IF (APPLE) +INCLUDE_DIRECTORIES( /usr/local/include/ ) +SET(LIBRARYS_MY /usr/local/lib/libqingstor.dylib) +ELSEIF(WIN32) +INCLUDE_DIRECTORIES(${VC_DIR}/include/) +INCLUDE_DIRECTORIES( ../../include/) +SET(LIBRARYS_MY qingstor.lib ${VC_DIR}/lib/libcurl.lib ${VC_DIR}/lib/libeay32.lib ${VC_DIR}/lib/ssleay32.lib ${VC_DIR}/lib/pthreadVC2.lib) +ELSE() +SET(LIBRARYS_MY /usr/local/lib/libqingstor.so) +ENDIF() + +ADD_EXECUTABLE(Sample_sdk_c ${SRC_LIST}) + +TARGET_LINK_LIBRARIES(Sample_sdk_c ${LIBRARYS_MY}) diff --git a/samples/samples_sdk_c/main.c b/samples/samples_sdk_c/main.c new file mode 100644 index 0000000..27a5fe6 --- /dev/null +++ b/samples/samples_sdk_c/main.c @@ -0,0 +1,308 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or at: +// | +// | http://www.apache.org/licenses/LICENSE-2.0 +// | +// | Unless required by applicable law or agreed to in writing, software +// | distributed under the License is distributed on an "AS IS" BASIS, +// | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// | See the License for the specific language governing permissions and +// | limitations under the License. +// +------------------------------------------------------------------------- + +// +------------------------------------------------------------------------- +// | This Example shows how to use the API interface. +// | For more information, please refer to URL : +// | +// | You should configure the following environment variables to ensure the +// | smooth execution of the program: +// | QINGSTOR_CONFIG_PATH : QingStor config file path +// | QINGSTOR_BUCKET_NAME : QingStor bucket name +// | QINGSTOR_ZONE_NAME : QingStor zone name +// +------------------------------------------------------------------------- +#include +#include "qingstor/service_with_c_style/QsList.h" +#include "qingstor/service_with_c_style/QingStorCStyle.h" + +void ShowHow2Do_InitiateMultipartUpload(qs_context_handle context_hdl, char* objectkey, char** uploadID) +{ + if(context_hdl.pQsBucket == NULL || context_hdl.pQsService == NULL){ + return; + } + + qs_initiate_multipart_upload_input_t input; + qs_initiate_multipart_upload_output_t output; + init_initiate_multipart_upload_input (&input); + + QsError err = qs_initiate_multipart_upload(objectkey, &input, &output, context_hdl); + if (QS_ERR_NO_ERROR == err && output.response_code == 200) + { + printf("uploadID is %s\n",output.upload_id); + *uploadID = (char*)malloc(strlen(output.upload_id) + 1); + memset((*uploadID), 0, strlen(output.upload_id) + 1); + memcpy((*uploadID), output.upload_id, strlen(output.upload_id)); + } + + release_initiate_multipart_upload_output(&output); + + printf("Initiate Multipart Upload is finished\n"); + return; +} + +void ShowHow2Do_UploadMultipart(qs_context_handle context_hdl, char* objectkey, char* uploadID ,int partNumber) +{ + if(context_hdl.pQsBucket == NULL || context_hdl.pQsService == NULL){ + return; + } + + qs_upload_multipart_input_t input; + qs_upload_multipart_output_t output; + init_upload_multipart_input (&input); + + long length = 5 * 1024 * 1024; //fiveMbSize + int part_number = partNumber; + input.bodybuf = (char *)malloc(length); + memset(input.bodybuf, 0, length); + input.bufLength = &length; + input.content_length = &length; + input.part_number = &part_number; + input.upload_id = uploadID; + + QsError err = qs_upload_multipart (objectkey, &input, &output, context_hdl); + if (QS_ERR_NO_ERROR == err) + { + // print sth + printf("Part %d is finished.\n",partNumber); + } + + // when api finish, you should release resource. + if(input.bodybuf) + { + free(input.bodybuf); + input.bodybuf = NULL; + } + + release_upload_multipart_output(&output); + + return; +} + +void ShowHow2Do_CompleteMultipartUpload(qs_context_handle context_hdl, char* objectkey, char* uploadID, qs_list_t * objectParts) +{ + if (context_hdl.pQsBucket == NULL || context_hdl.pQsService == NULL){ + return; + } + + qs_complete_multipart_upload_input_t input; + qs_complete_multipart_upload_output_t output; + init_complete_multipart_upload_input(&input); + + input.object_parts = objectParts; + input.upload_id = uploadID; + + QsError err = qs_complete_multipart_upload(objectkey, &input, &output, context_hdl); + if (QS_ERR_NO_REQUIRED_PARAMETER == err) + { + printf("%s\n", "The input object lacks some of the parameters that must be filled in."); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + int responsecode = output.response_code; + printf("the ListObject responsecode is %d\n", responsecode); + } + + release_complete_multipart_upload_output(&output); + + return; +} + +void ShowHow2Do_ListObjects(qs_context_handle context_hdl) +{ + if(context_hdl.pQsBucket == NULL || context_hdl.pQsService == NULL){ + return; + } + + // List Objects + qs_list_objects_input_t input; + qs_list_objects_output_t output; + init_list_objects_input(&input); + // if you want limit the maximum number of object in response, you can set "Limit" paramter. + // the default value is 200, maximum allowable set 1000 + int limitNum = 100; + input.limit = &limitNum;// + + QsError err = qs_list_objects(&input, &output, context_hdl); + + + if(QS_ERR_NO_ERROR == err) + { + qs_list_t *keys = output.keys; + int count = 0; + qs_key_item_t *pos; + qs_list_for_each_entry(qs_key_item_t, pos, keys) + { + count++; + } + printf("Got %d objects\n" ,count); + } + + if (QS_ERR_UNEXCEPTED_RESPONSE == err ) + { + printf("request_id = %s , with detail message : %s\n" , output.error_info.request_id, output.error_info.message); + } + + release_list_objects_output(&output); + + + return; +} + + +void ShowHow2Do_MultipartUploadObject(qs_context_handle context_hdl, char* objectkey) +{ + if(context_hdl.pQsBucket == NULL || context_hdl.pQsService == NULL){ + return; + } + + char* uploadID = NULL; + + ShowHow2Do_InitiateMultipartUpload(context_hdl , objectkey , &uploadID); + + ShowHow2Do_UploadMultipart(context_hdl, objectkey, uploadID ,1); + + ShowHow2Do_UploadMultipart(context_hdl, objectkey, uploadID ,2); + + qs_list_t object_parts_list; + qs_list_init(&object_parts_list); + qs_object_part_item_t object_parts_item_1, object_parts_item_2; + qs_object_part_t object_parts_1, object_parts_2; + init_object_part(&object_parts_1); + init_object_part(&object_parts_2); + + int part_number_1 = 1; + int part_number_2 = 2; + object_parts_1.part_number = &part_number_1; + object_parts_2.part_number = &part_number_2; + object_parts_item_1.content = &object_parts_1; + object_parts_item_2.content = &object_parts_2; + qs_list_append(&object_parts_item_1.node, &object_parts_list); + qs_list_append(&object_parts_item_2.node, &object_parts_list); + + ShowHow2Do_CompleteMultipartUpload(context_hdl, objectkey, uploadID, &object_parts_list); + + if(uploadID) + { + free(uploadID); + } + + return; +} + + +void ShowHow2Do_GetObject(qs_context_handle context_hdl, char* objectkey) +{ + if(context_hdl.pQsBucket == NULL || context_hdl.pQsService == NULL){ + return; + } + + qs_get_object_input_t input; + qs_get_object_output_t output; + init_get_object_input (&input); + + QsError err = qs_get_object(objectkey, &input, &output, context_hdl); + if(QS_ERR_NO_REQUIRED_PARAMETER == err) + { + printf("%s\n" , "The input object lacks some of the parameters that must be filled in."); + } + + if (QS_ERR_UNEXCEPTED_RESPONSE == err ) + { + printf("request_id = %s , with detail message : %s\n" , output.error_info.request_id, output.error_info.message); + } + + if (output.bodybuf) + { + printf("The length of object is : %ld\n", *output.bufLength); + } + + release_get_object_output(&output); + + return; +} + + +void ShowHow2Do_DeleteObject(qs_context_handle context_hdl, char* objectkey) +{ + if(context_hdl.pQsBucket == NULL || context_hdl.pQsService == NULL){ + return; + } + + qs_delete_object_input_t input; + qs_delete_object_output_t output; + init_delete_object_input (&input); + + QsError err = qs_delete_object(objectkey, &input, &output, context_hdl); + if(QS_ERR_NO_REQUIRED_PARAMETER == err) + { + printf("%s\n" , "The input object lacks some of the parameters that must be filled in."); + } + + if (QS_ERR_UNEXCEPTED_RESPONSE == err ) + { + printf("request_id = %s , with detail message : %s\n" , output.error_info.request_id, output.error_info.message); + } + + printf("object(%s) has been deleted.\n" , objectkey); + + release_delete_object_output(&output); + + return; +} + +int main() +{ + // Read necessary information from envirox nment variables. + char *strConfigPath ="/etc/qingstor/config.yaml";// getenv("QINGSTOR_CONFIG_PATH"); + char *strBucketName = "huang-stor";//getenv("QINGSTOR_BUCKET_NAME"); + char *strZone = "zone";//getenv("QINGSTOR_ZONE_NAME"); + if(!strConfigPath || !strBucketName || !strZone) + { + printf("Envionment variables are missing : QINGSTOR_CONFIG_PATH or QINGSTOR_BUCKET_NAME or QINGSTOR_ZONE_NAME.\n"); + return 1; + } + printf("QINGSTOR_CONFIG_PATH: %s.\n",strConfigPath); + printf("QINGSTOR_BUCKET_NAME: %s.\n",strBucketName); + printf("QINGSTOR_ZONE_NAME: %s.\n",strZone); + + char* objectkey = "QingStor_SDK_Test_File"; + + qs_init_sdk("/tmp/", Debug, 1); + + // Global initialization only needs to be initialized once + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + // Valid log levels are "none","debug", "info", "warn", "error", and "fatal".(default value is "None") + + ShowHow2Do_ListObjects(context_hdl); + + ShowHow2Do_MultipartUploadObject(context_hdl, objectkey); + + ShowHow2Do_GetObject(context_hdl, objectkey); + + ShowHow2Do_DeleteObject(context_hdl, objectkey); + + qs_release_service(context_hdl); + + qs_shutdown_sdk(1); + + return 0; +} + + + + + + diff --git a/samples/samples_sdk_cpp/CMakeLists.txt b/samples/samples_sdk_cpp/CMakeLists.txt new file mode 100644 index 0000000..b7f3ed8 --- /dev/null +++ b/samples/samples_sdk_cpp/CMakeLists.txt @@ -0,0 +1,31 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +PROJECT(Sample_sdk_cpp) + +SET(CMAKE_BUILD_TYPE "Debug") +IF(WIN32) +ELSE() +SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb -L /lib64 -l pthread") +SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall") +ENDIF() + +GET_FILENAME_COMPONENT(COMPILER_DIR ${CMAKE_CXX_COMPILER} DIRECTORY) +GET_FILENAME_COMPONENT(VC_DIR ${COMPILER_DIR} DIRECTORY) + +SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" $ {CMAKE_MODULE_PATH}) +SET(SRC_LIST main.cpp) + +IF (APPLE) +INCLUDE_DIRECTORIES( /usr/local/include/ ) +SET(LIBRARYS_MY /usr/local/lib/libqingstor.dylib) +ELSEIF(WIN32) +INCLUDE_DIRECTORIES(${VC_DIR}/include/) +INCLUDE_DIRECTORIES( ../../include/) +SET(LIBRARYS_MY qingstor.lib ${VC_DIR}/lib/libcurl.lib ${VC_DIR}/lib/libeay32.lib ${VC_DIR}/lib/ssleay32.lib ${VC_DIR}/lib/pthreadVC2.lib) +ELSE() +SET(LIBRARYS_MY /usr/local/lib/libqingstor.so) +ENDIF() + +ADD_EXECUTABLE(Sample_sdk_cpp ${SRC_LIST}) + +TARGET_LINK_LIBRARIES(Sample_sdk_cpp ${LIBRARYS_MY}) diff --git a/samples/samples_sdk_cpp/main.cpp b/samples/samples_sdk_cpp/main.cpp new file mode 100644 index 0000000..5196530 --- /dev/null +++ b/samples/samples_sdk_cpp/main.cpp @@ -0,0 +1,296 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or at: +// | +// | http://www.apache.org/licenses/LICENSE-2.0 +// | +// | Unless required by applicable law or agreed to in writing, software +// | distributed under the License is distributed on an "AS IS" BASIS, +// | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// | See the License for the specific language governing permissions and +// | limitations under the License. +// +------------------------------------------------------------------------- + +// +------------------------------------------------------------------------- +// | This Example shows how to use the API interface. +// | For more information, please refer to URL : +// | +// | You should configure the following environment variables to ensure the +// | smooth execution of the program: +// | QINGSTOR_CONFIG_PATH : QingStor config file path +// | QINGSTOR_BUCKET_NAME : QingStor bucket name +// | QINGSTOR_ZONE_NAME : QingStor zone name +// +------------------------------------------------------------------------- + +#include +#include +#include +#include + +using namespace QingStor; + +static std::iostream* Create5MbStream4UploadPart(const std::string partTag) +{ + size_t fiveMbSize = 5 * 1024 * 1024; + std::stringstream patternStream; + patternStream << "Multi-Part upload Test Part " << partTag << ":" << std::endl; + std::string pattern = patternStream.str(); + std::string scratchString; + scratchString.reserve(fiveMbSize); + // 5MB is a hard minimum for multi part uploads; make sure the final string is at least that long + size_t patternCopyCount = static_cast< size_t >( fiveMbSize / pattern.size() + 1 ); + for(size_t i = 0; i < patternCopyCount; ++i) + { + scratchString.append(pattern); + } + std::iostream* streamPtr = new std::stringstream(scratchString); + streamPtr->seekg(0); + streamPtr->seekp(0, std::ios_base::end); + return streamPtr; +} + + +void ShowHow2Do_InitiateMultipartUpload(Bucket * qsBucket, std::string &objectkey, std::string &uploadID) +{ + if(!qsBucket) + { + return; + } + InitiateMultipartUploadInput input; + InitiateMultipartUploadOutput output; + QsError err = qsBucket->InitiateMultipartUpload (objectkey, input, output); + if (QS_ERR_NO_ERROR == err) + { + // If Success. + uploadID = output.GetUploadID(); + } + else if(QS_ERR_NO_REQUIRED_PARAMETER == err) + { + printf("%s\n" , "The input object lacks some of the parameters that must be filled in."); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + ResponseErrorInfo errorInfo = output.GetResponseErrInfo(); + printf("request_id = %s , with detail message : %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str()); + } + return; +} + + +void ShowHow2Do_UploadMultipart(Bucket * qsBucket, std::string &objectkey, std::string &uploadID ,int partNumber) +{ + if(!qsBucket) + { + return; + } + UploadMultipartInput input; + UploadMultipartOutput output; + // objectStream can be filestream or stringstream. + std::iostream* objectStream = Create5MbStream4UploadPart("1"); + objectStream->seekg(0, objectStream->end); + size_t streamSize = objectStream->tellg(); + objectStream->seekg(0, objectStream->beg); + // The content length must be set. + input.SetContentLength(streamSize); + input.SetBody (objectStream); + input.SetPartNumber (partNumber); + input.SetUploadID (uploadID); + QsError err = qsBucket->UploadMultipart (objectkey, input, output); + if(QS_ERR_NO_REQUIRED_PARAMETER == err) + { + printf("%s\n" , "The input object lacks some of the parameters that must be filled in."); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + ResponseErrorInfo errorInfo = output.GetResponseErrInfo(); + printf("request_id = %s , with detail message : %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str()); + } + printf("Part %d is finished.\n", partNumber); + // when api finish, you should release resource. + delete objectStream; + return; +} + + +void ShowHow2Do_CompleteMultipartUpload(Bucket * qsBucket, std::string &objectkey, std::string &uploadID, std::vector &objectParts) +{ + if(!qsBucket) + { + return; + } + CompleteMultipartUploadInput input; + CompleteMultipartUploadOutput output; + input.SetUploadID (uploadID); + input.SetObjectParts(objectParts); + QsError err = qsBucket->CompleteMultipartUpload (objectkey, input, output); + if(QS_ERR_NO_REQUIRED_PARAMETER == err) + { + printf("%s\n" , "The input object lacks some of the parameters that must be filled in."); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + ResponseErrorInfo errorInfo = output.GetResponseErrInfo(); + printf("request_id = %s , with detail message : %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str()); + } + return; +} + + +void ShowHow2Do_ListObjects(Bucket * qsBucket) +{ + if(!qsBucket) + { + return; + } + // List Objects + ListObjectsInput input; + ListObjectsOutput output; + // if you want limit the maximum number of object in response, you can set "Limit" paramter. + // the default value is 200, maximum allowable set 1000 + input.SetLimit(100);// + QsError err = qsBucket->ListObjects(input, output); + if(QS_ERR_NO_REQUIRED_PARAMETER == err) + { + printf("%s\n" , "The input object lacks some of the parameters that must be filled in."); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + ResponseErrorInfo errorInfo = output.GetResponseErrInfo(); + printf("request_id = %s , with detail message : %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str()); + } + if (QS_ERR_NO_ERROR != err) + { + return; + } + std::vector keys = output.GetKeys(); + printf("Got %ld objects\n" ,keys.size()); + return; +} + +void ShowHow2Do_MultipartUploadObject(Bucket * qsBucket, std::string &objectkey) +{ + if(!qsBucket) + { + return; + } + std::string uploadID = ""; + ShowHow2Do_InitiateMultipartUpload(qsBucket, objectkey, uploadID); + ShowHow2Do_UploadMultipart(qsBucket, objectkey, uploadID ,1); + ShowHow2Do_UploadMultipart(qsBucket, objectkey, uploadID ,2); + std::vector objectParts; + ObjectPartType part1,part2; + part1.SetPartNumber(1); + part2.SetPartNumber(2); + objectParts.push_back(part1); + objectParts.push_back(part2); + ShowHow2Do_CompleteMultipartUpload(qsBucket, objectkey, uploadID, objectParts); + return; +} + +void ShowHow2Do_GetObject(Bucket * qsBucket, std::string &objectkey) +{ + if(!qsBucket) + { + return; + } + GetObjectInput input; + GetObjectOutput output; + QsError err = qsBucket->GetObject(objectkey, input, output); + if(QS_ERR_NO_REQUIRED_PARAMETER == err) + { + printf("%s\n" , "The input object lacks some of the parameters that must be filled in."); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + ResponseErrorInfo errorInfo = output.GetResponseErrInfo(); + printf("request_id = %s , with detail message : %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str()); + } + if (QS_ERR_NO_ERROR != err) + { + return; + } + size_t streamSize = 0; + std::iostream* objectStream = output.GetBody(); + if(objectStream) + { + objectStream->seekg(0, objectStream->end); + streamSize = objectStream->tellg(); + } + delete objectStream; + printf("The length of object is : %ld\n" , streamSize); + return; +} + +void ShowHow2Do_DeleteObject(Bucket * qsBucket, std::string &objectkey) +{ + if(!qsBucket) + { + return; + } + DeleteObjectInput input; + DeleteObjectOutput output; + QsError err = qsBucket->DeleteObject(objectkey, input, output); + if(QS_ERR_NO_REQUIRED_PARAMETER == err) + { + printf("%s\n" , "The input object lacks some of the parameters that must be filled in."); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + ResponseErrorInfo errorInfo = output.GetResponseErrInfo(); + printf("request_id = %s , with detail message : %s\n" , errorInfo.requestID.c_str(), errorInfo.message.c_str()); + } + if (QS_ERR_NO_ERROR != err) + { + return; + } + printf("object(%s) has been deleted.\n" , objectkey.c_str()); + return; +} + +int main() +{ + // Read necessary information from environment variables. + char *strConfigPath = getenv("QINGSTOR_CONFIG_PATH"); + char *strBucketName = getenv("QINGSTOR_BUCKET_NAME"); + char *strZone = getenv("QINGSTOR_ZONE_NAME"); + if(!strConfigPath || !strBucketName || !strZone) + { + printf("Envionment variables are missing : QINGSTOR_CONFIG_PATH or QINGSTOR_BUCKET_NAME or QINGSTOR_ZONE_NAME.\n"); + return 1; + } + printf("QINGSTOR_CONFIG_PATH: %s.\n",strConfigPath); + printf("QINGSTOR_BUCKET_NAME: %s.\n",strBucketName); + printf("QINGSTOR_ZONE_NAME: %s.\n",strZone); + // Global initialization only needs to be initialized once + // Valid log levels are "none","debug", "info", "warn", "error", and "fatal".(default value is "None") + QingStor::SDKOptions sdkOptions; + sdkOptions.logLevel = Debug; + sdkOptions.logPath = "/tmp/"; + InitializeSDK(sdkOptions); + // Create QsConfig object , and init it with config info loaded form ConfigPath. + // You can also set up the config configuration item separately. + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath); + // Create Bucket object. + Bucket * qsBucket = new Bucket(qsConfig, strBucketName, strZone); + ShowHow2Do_ListObjects(qsBucket); + std::string objectkey = "QingStor_SDK_Test_File"; + ShowHow2Do_MultipartUploadObject(qsBucket, objectkey); + ShowHow2Do_GetObject(qsBucket, objectkey); + ShowHow2Do_DeleteObject(qsBucket, objectkey); + ShutdownSDK(sdkOptions); + if(qsBucket) + { + delete qsBucket; + } + return 0; +} + + + + + + diff --git a/specs b/specs new file mode 160000 index 0000000..fea6e24 --- /dev/null +++ b/specs @@ -0,0 +1 @@ +Subproject commit fea6e2473efefa71558446b31fa989b639bd88e4 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..9c72f16 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,123 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +SET(libqingstor_VERSION_MAJOR 0) +SET(libqingstor_VERSION_MINOR 0) +SET(libqingstor_VERSION_PATCH 1) +SET(libqingstor_VERSION_STRING "${libqingstor_VERSION_MAJOR}.${libqingstor_VERSION_MINOR}.${libqingstor_VERSION_PATCH}") +SET(libqingstor_VERSION_API 1) + +GET_FILENAME_COMPONENT(PARENT_DIR ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY) +SET(libqingstor_ROOT_SOURCES_DIR ${PARENT_DIR}/src) +SET(libqingstor_INCLUDE_DIR ${PARENT_DIR}/include ${libqingstor_ROOT_SOURCES_DIR}/include) + +GET_FILENAME_COMPONENT(COMPILER_DIR ${CMAKE_CXX_COMPILER} DIRECTORY) +GET_FILENAME_COMPONENT(VC_DIR ${COMPILER_DIR} DIRECTORY) + +IF(WIN32) + SET(WS2_LIBRARIES Ws2_32.lib) + SET(WINLDAP_LIBRARIES Wldap32.lib) + # force to compile with W0 + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W0") +ELSE() + SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wno-deprecated-declarations -g2 -ggdb") + SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wno-deprecated-declarations") +ENDIF() + +IF(APPLE) + SET(CMAKE_MACOSX_RPATH 1) +ENDIF() + +IF(ENABLE_DEBUG) + SET(libqingstor_VERSION_STRING "${libqingstor_VERSION_STRING}d") +ENDIF(ENABLE_DEBUG) + + +CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/QsSdkOption.h.in" "${PARENT_DIR}/include/QsSdkOption.h") + +AUTO_SOURCES(files "external/yaml/*.c" "RECURSE" "${CMAKE_CURRENT_SOURCE_DIR}") +LIST(APPEND libqingstor_SOURCES ${files}) + +AUTO_SOURCES(files "external/lib_json/*.cpp" "RECURSE" "${CMAKE_CURRENT_SOURCE_DIR}") +LIST(APPEND libqingstor_SOURCES ${files}) + +AUTO_SOURCES(files "config/*.cpp" "RECURSE" "${CMAKE_CURRENT_SOURCE_DIR}") +LIST(APPEND libqingstor_SOURCES ${files}) + +AUTO_SOURCES(files "http/*.cpp" "RECURSE" "${CMAKE_CURRENT_SOURCE_DIR}") +LIST(APPEND libqingstor_SOURCES ${files}) + +AUTO_SOURCES(files "utils/*.cpp" "RECURSE" "${CMAKE_CURRENT_SOURCE_DIR}") +LIST(APPEND libqingstor_SOURCES ${files}) + +AUTO_SOURCES(files "request/*.cpp" "RECURSE" "${CMAKE_CURRENT_SOURCE_DIR}") +LIST(APPEND libqingstor_SOURCES ${files}) + +AUTO_SOURCES(files "service/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}") +LIST(APPEND libqingstor_SOURCES ${files}) + +# if BUILD_C_STYLE_INTERFACE == ON, install header files with C style. +IF(BUILD_C_STYLE_INTERFACE) +AUTO_SOURCES(files "service/service_with_c_style/*.cpp" "RECURSE" "${CMAKE_CURRENT_SOURCE_DIR}") +LIST(APPEND libqingstor_SOURCES ${files}) +ENDIF() + +AUTO_SOURCES(files "signer/*.cpp" "RECURSE" "${CMAKE_CURRENT_SOURCE_DIR}") +LIST(APPEND libqingstor_SOURCES ${files}) + +AUTO_SOURCES(files "*.h" "${libqingstor_INCLUDE_DIR}") +SET(HEADER ${files}) + +AUTO_SOURCES(files "types/*.h" "${libqingstor_INCLUDE_DIR}") +SET(HEADER_TYPES ${files}) + +# if BUILD_C_STYLE_INTERFACE == ON, install header files with C style. +IF(BUILD_C_STYLE_INTERFACE) +AUTO_SOURCES(files "service_with_c_style/*.h" "${libqingstor_INCLUDE_DIR}") +SET(HEADER_CStyle ${files}) + +AUTO_SOURCES(files "service_with_c_style/types/*.h" "${libqingstor_INCLUDE_DIR}") +SET(HEADER_TYPES_CStyle ${files}) +ENDIF() + +INCLUDE_DIRECTORIES(${libqingstor_INCLUDE_DIR}) +INCLUDE_DIRECTORIES(${libqingstor_INCLUDE_DIR}/external) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +INCLUDE_DIRECTORIES(${CURL_INCLUDE_DIR}) +INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) +INCLUDE_DIRECTORIES(${VC_DIR}/include) + +# On windows, generate static library +IF (WIN32) + ADD_LIBRARY(libqingstor-static STATIC ${libqingstor_SOURCES}) + SET_TARGET_PROPERTIES(libqingstor-static PROPERTIES OUTPUT_NAME "qingstor") +ELSE() +#On other platform ,generate dynamic library + + ADD_LIBRARY(libqingstor-shared SHARED ${libqingstor_SOURCES}) + TARGET_LINK_LIBRARIES(libqingstor-shared ${CURL_LIBRARIES}) + TARGET_LINK_LIBRARIES(libqingstor-shared ${OPENSSL_SSL_LIBRARIES}) + TARGET_LINK_LIBRARIES(libqingstor-shared ${OPENSSL_CRYPTO_LIBRARIES}) + SET_TARGET_PROPERTIES(libqingstor-shared PROPERTIES OUTPUT_NAME "qingstor") + SET_TARGET_PROPERTIES(libqingstor-shared PROPERTIES + VERSION ${libqingstor_VERSION_MAJOR}.${libqingstor_VERSION_MINOR}.${libqingstor_VERSION_PATCH} + SOVERSION ${libqingstor_VERSION_API}) + # install lib files. + INSTALL(TARGETS libqingstor-shared + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib) +ENDIF() + +# install header files. +INSTALL(FILES ${HEADER} DESTINATION include/qingstor) +INSTALL(FILES ${HEADER_TYPES} DESTINATION include/qingstor/types) + +# if BUILD_C_STYLE_INTERFACE == ON, install header files with C style. +IF(BUILD_C_STYLE_INTERFACE) +INSTALL(FILES ${HEADER_CStyle} DESTINATION include/qingstor/service_with_c_style) +INSTALL(FILES ${HEADER_TYPES_CStyle} DESTINATION include/qingstor/service_with_c_style/types) +ENDIF() + +SET(libqingstor_SOURCES ${libqingstor_SOURCES} PARENT_SCOPE) +SET(libqingstor_PLATFORM_HEADER_DIR ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE) +SET(libqingstor_ROOT_SOURCES_DIR ${libqingstor_ROOT_SOURCES_DIR} PARENT_SCOPE) +SET(libqingstor_VERSION_STRING ${libqingstor_VERSION_STRING} PARENT_SCOPE) diff --git a/src/QsSdkOption.h.in b/src/QsSdkOption.h.in new file mode 100644 index 0000000..c316332 --- /dev/null +++ b/src/QsSdkOption.h.in @@ -0,0 +1,20 @@ +#pragma once + +#cmakedefine BUILD_C_STYLE_INTERFACE + +#define QS_SDK_API + +#ifdef _WIN32 +#include +#endif + +typedef enum LogLevel +{ + None = 0, + Fatal = 1, + Error = 2, + Warning = 3, + Info = 4, + Debug = 5, + Verbose = 6 +}LogLevel; diff --git a/src/config/QsConfig.cpp b/src/config/QsConfig.cpp new file mode 100644 index 0000000..883f99c --- /dev/null +++ b/src/config/QsConfig.cpp @@ -0,0 +1,258 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or at: +// | +// | http://www.apache.org/licenses/LICENSE-2.0 +// | +// | Unless required by applicable law or agreed to in writing, software +// | distributed under the License is distributed on an "AS IS" BASIS, +// | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// | See the License for the specific language governing permissions and +// | limitations under the License. +// +------------------------------------------------------------------------- + +#include +#include +#include "QsConfig.h" +#include "StringUtils.h" +#include + +namespace QingStor +{ + +static const char *CONFIG_KEY_ACCESS_KEY_ID = "access_key_id"; + +static const char *CONFIG_KEY_SECRET_ACCESS_KEY = "secret_access_key"; + +static const char *CONFIG_KEY_HOST = "host"; + +static const char *CONFIG_KEY_PORT = "port"; + +static const char *CONFIG_KEY_PROTOCOL = "protocol"; + +static const char *CONFIG_KEY_CONNECTION_RETRIES = "connection_retries"; + +static const char *CONFIG_KEY_ADDITIONAL_USER_AGENT = "additional_user_agent"; + +static const char *CONFIG_KEY_TIMEOUT_PERIOD = "timeOutPeriod"; + +// Default value + +static const char *DEFAULT_HOST = "qingstor.com"; + +static const char *DEFAULT_PROTOCOL = "https"; + +static const char *DEFAULT_ADDITIONAL_USER_AGENT = ""; + +static int DEFAULT_RETRIES = 3; + +static int DEFAULT_PORT = 443; + +static int DEFAULT_TIMEOUT_PERIOD = 3; + +QsConfig::QsConfig(const std::string & access_key_id, const std::string & secret_access_key) + : additionalUserAgent(DEFAULT_ADDITIONAL_USER_AGENT), + accessKeyId(access_key_id),secretAccessKey(secret_access_key), + host(DEFAULT_HOST),protocol(DEFAULT_PROTOCOL), + port(DEFAULT_PORT),connectionRetries(DEFAULT_RETRIES), + timeOutPeriod(DEFAULT_TIMEOUT_PERIOD) +{ +} + +QsError QsConfig::LoadConfigFile(const std::string &config_file) +{ + FILE *fh = NULL; + yaml_parser_t parser; + yaml_token_t token; + std::map kvs; + std::string token_key; + std::string token_value; + bool reach_key = false; + bool reach_value = false; + /* Initialize parser */ + if (!yaml_parser_initialize(&parser)) + { + LOG_FATAL << "couldn't initialize yaml parser"; + return QS_ERR_INVAILD_CONFIG_FILE; + } + /* Open configuration file */ + if ((fh = fopen(config_file.c_str(), "rb")) == NULL) + { + yaml_parser_delete(&parser); + LOG_FATAL << "couldn't open configure file " << config_file.c_str(); + return QS_ERR_INVAILD_CONFIG_FILE; + } + /* Set input file */ + yaml_parser_set_input_file(&parser, fh); + do + { + yaml_parser_scan(&parser, &token); + switch (token.type) + { + case YAML_STREAM_START_TOKEN: + case YAML_STREAM_END_TOKEN: + case YAML_BLOCK_SEQUENCE_START_TOKEN: + case YAML_BLOCK_ENTRY_TOKEN: + case YAML_BLOCK_END_TOKEN: + case YAML_BLOCK_MAPPING_START_TOKEN: + break; + case YAML_KEY_TOKEN: + { + reach_key = true; + } + break; + case YAML_VALUE_TOKEN: + { + reach_value = true; + } + break; + case YAML_SCALAR_TOKEN: + { + bool config_invalid = false; + if (reach_key) + { + token_key = std::string((const char *)(token.data.scalar.value)); + reach_key = false; + break; + } + else if (reach_value) + { + token_value = std::string((const char *)(token.data.scalar.value)); + reach_value = false; + if (token_key.empty() || token_value.empty()) + { + config_invalid = true; + } + } + else + { + config_invalid = true; + } + if (config_invalid) + { + yaml_token_delete(&token); + yaml_parser_delete(&parser); + fclose(fh); + LOG_FATAL << "YAML configuration is invalid"; + return QS_ERR_INVAILD_CONFIG_FILE; + } + else + { + kvs.insert(std::pair(token_key, token_value)); + token_key.clear(); + token_value.clear(); + } + } + break; + default: + { + yaml_token_delete(&token); + yaml_parser_delete(&parser); + fclose(fh); + LOG_FATAL << "YAML configuration is invalid with token type" << token.type; + return QS_ERR_INVAILD_CONFIG_FILE; + } + break; + } + if (token.type != YAML_STREAM_END_TOKEN) + { + yaml_token_delete(&token); + } + } + while (token.type != YAML_STREAM_END_TOKEN); + yaml_token_delete(&token); + yaml_parser_delete(&parser); + fclose(fh); + /* Go through the interested configurations */ + if (kvs[std::string(CONFIG_KEY_ACCESS_KEY_ID)].empty()) + { + LOG_FATAL << "YAML configuration is invalid with token type" << token.type; + return QS_ERR_INVAILD_CONFIG_FILE; + } + else + { + accessKeyId = kvs[std::string(CONFIG_KEY_ACCESS_KEY_ID)]; + } + if (kvs[std::string(CONFIG_KEY_SECRET_ACCESS_KEY)].empty()) + { + return QS_ERR_INVAILD_CONFIG_FILE; + } + else + { + secretAccessKey = kvs[std::string(CONFIG_KEY_SECRET_ACCESS_KEY)]; + } + if (kvs[std::string(CONFIG_KEY_HOST)].empty()) + { + host = DEFAULT_HOST; + } + else + { + host = kvs[std::string(CONFIG_KEY_HOST)]; + } + if (kvs[std::string(CONFIG_KEY_PORT)].empty()) + { + port = DEFAULT_PORT; + } + else + { + std::string port_str = kvs[std::string(CONFIG_KEY_PORT)]; + int tmp_prot = atoi(port_str.c_str()); + if (tmp_prot <= 0 || tmp_prot > 65535) + { + LOG_WARNING << "Configuration Port" << port_str.c_str() << "is invalid, using default vaule:" << DEFAULT_PORT; + tmp_prot = DEFAULT_PORT; + } + port = tmp_prot; + } + if (kvs[std::string(CONFIG_KEY_PROTOCOL)].empty()) + { + protocol = DEFAULT_PROTOCOL; + } + else + { + protocol = kvs[std::string(CONFIG_KEY_PROTOCOL)]; + } + if (kvs[std::string(CONFIG_KEY_CONNECTION_RETRIES)].empty()) + { + connectionRetries = 3; + } + else + { + std::string retries_str = kvs[std::string(CONFIG_KEY_CONNECTION_RETRIES)]; + int retries = atoi(retries_str.c_str()); + if (retries <= 0 || retries > 16) + { + LOG_WARNING << "Configuration connection retries" << retries_str.c_str() << " is invalid, using default value:" << DEFAULT_RETRIES; + retries = DEFAULT_RETRIES; + } + connectionRetries = retries; + } + if (kvs[std::string(CONFIG_KEY_TIMEOUT_PERIOD)].empty()) + { + timeOutPeriod = 3; + } + else + { + std::string timeOutPeriod_str = kvs[std::string(CONFIG_KEY_TIMEOUT_PERIOD)]; + int timeOut = atoi(timeOutPeriod_str.c_str()); + if (connectionRetries <= 0) + { + LOG_WARNING << "Configuration connection retries" << timeOutPeriod_str.c_str() << " is invalid, using default value:" << DEFAULT_RETRIES; + timeOutPeriod = DEFAULT_TIMEOUT_PERIOD; + } + timeOutPeriod = timeOut; + } + if (kvs[std::string(CONFIG_KEY_ADDITIONAL_USER_AGENT)].empty()) + { + additionalUserAgent = ""; + } + else + { + additionalUserAgent = kvs[std::string(CONFIG_KEY_ADDITIONAL_USER_AGENT)]; + } + return QS_ERR_NO_ERROR; +} +} diff --git a/src/external/lib_json/json_reader.cpp b/src/external/lib_json/json_reader.cpp new file mode 100644 index 0000000..d9f4700 --- /dev/null +++ b/src/external/lib_json/json_reader.cpp @@ -0,0 +1,2281 @@ +// Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors +// Copyright (C) 2016 InfoTeCS JSC. All rights reserved. +// 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__) || defined(__QNXNTO__) +#define snprintf snprintf +#elif __cplusplus >= 201103L +#if !defined(__MINGW32__) && !defined(__CYGWIN__) +#define snprintf std::snprintf +#endif +#endif + +#if defined(__QNXNTO__) +#define sscanf std::sscanf +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile time to change the stack limit +#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT) +#define JSONCPP_DEPRECATED_STACK_LIMIT 1000 +#endif + +static size_t const stackLimit_g = JSONCPP_DEPRECATED_STACK_LIMIT; // 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), + allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} + +Features Features::all() +{ + return Features(); +} + +Features Features::strictMode() +{ + Features features; + features.allowComments_ = false; + features.strictRoot_ = true; + features.allowDroppedNullPlaceholders_ = false; + features.allowNumericKeys_ = false; + return features; +} + +// Implementation of class Reader +// //////////////////////////////// + +bool Reader::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_.assign(document.begin(), document.end()); + 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 JSONCPP_STRING is reference-counted, this at least does not + // create an extra copy. + JSONCPP_STRING doc; + std::getline(sin, doc, (char)EOF); + return parse(doc.data(), doc.data() + doc.size(), 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_.clear(); + errors_.clear(); + while (!nodes_.empty()) + nodes_.pop(); + nodes_.push(&root); + 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() +{ + // readValue() may call itself only if it calls readObject() or ReadArray(). + // These methods execute nodes_.push() just before and nodes_.pop)() just after calling readValue(). + // parse() executes one nodes_.push(), so > instead of >=. + if (nodes_.size() > stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue()."); + Token token; + skipCommentTokens(token); + bool successful = true; + if (collectComments_ && !commentsBefore_.empty()) + { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_.clear(); + } + switch (token.type_) + { + case tokenObjectBegin: + successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenArrayBegin: + successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: + { + Value v(true); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenFalse: + { + Value v(false); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNull: + { + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + 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); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // Else, fall through... + default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return addError("Syntax error: value, object or array expected.", token); + } + if (collectComments_) + { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + 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; +} + +JSONCPP_STRING Reader::normalizeEOL(Reader::Location begin, Reader::Location end) +{ + JSONCPP_STRING normalized; + normalized.reserve(static_cast(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 JSONCPP_STRING& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) + { + assert(lastValue_ != 0); + lastValue_->setComment(normalized, placement); + } + else + { + commentsBefore_ += normalized; + } +} + +bool Reader::readCStyleComment() +{ + while ((current_ + 1) < 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; + JSONCPP_STRING name; + Value init(objectValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + 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.clear(); + 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 = JSONCPP_STRING(numberName.asCString()); + } + 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); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + skipSpaces(); + if (current_ != end_ && *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); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + 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(static_cast(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); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeDouble(Token& token, Value& decoded) +{ + double value = 0; + JSONCPP_STRING buffer(token.start_, token.end_); + JSONCPP_ISTRINGSTREAM is(buffer); + if (!(is >> value)) + return addError("'" + JSONCPP_STRING(token.start_, token.end_) + + "' is not a number.", + token); + decoded = value; + return true; +} + +bool Reader::decodeString(Token& token) +{ + JSONCPP_STRING decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) +{ + decoded.reserve(static_cast(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& ret_unicode) +{ + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", + token, + current); + int 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); + } + ret_unicode = static_cast(unicode); + return true; +} + +bool +Reader::addError(const JSONCPP_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) +{ + size_t const errorCount = 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 JSONCPP_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; +} + +JSONCPP_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 +JSONCPP_STRING Reader::getFormatedErrorMessages() const +{ + return getFormattedErrorMessages(); +} + +JSONCPP_STRING Reader::getFormattedErrorMessages() const +{ + JSONCPP_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; +} + +std::vector Reader::getStructuredErrors() const +{ + std::vector allErrors; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) + { + const ErrorInfo& error = *itError; + Reader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) +{ + ptrdiff_t const length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = end_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = 0; + errors_.push_back(info); + return true; +} + +bool Reader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) +{ + ptrdiff_t const length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length + || extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool Reader::good() const +{ + return !errors_.size(); +} + +// exact copy of Features +class OurFeatures +{ +public: + static OurFeatures all(); + 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::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 + { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + JSONCPP_STRING message; + }; + + OurReader(OurFeatures const& features); + bool parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments = true); + JSONCPP_STRING getFormattedErrorMessages() const; + std::vector getStructuredErrors() const; + bool pushError(const Value& value, const JSONCPP_STRING& message); + bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra); + bool good() 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_; + JSONCPP_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, JSONCPP_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 JSONCPP_STRING& message, Token& token, Location extra = 0); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + JSONCPP_STRING getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + static JSONCPP_STRING normalizeEOL(Location begin, Location end); + static bool containsNewLine(Location begin, Location end); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + JSONCPP_STRING document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + JSONCPP_STRING commentsBefore_; + + OurFeatures const features_; + bool collectComments_; +}; // OurReader + +// complete copy of Read impl, for OurReader + +bool OurReader::containsNewLine(OurReader::Location begin, OurReader::Location end) +{ + for (; begin < end; ++begin) + if (*begin == '\n' || *begin == '\r') + return true; + return false; +} + +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_.clear(); + errors_.clear(); + while (!nodes_.empty()) + nodes_.pop(); + nodes_.push(&root); + bool successful = readValue(); + Token token; + skipCommentTokens(token); + if (features_.failIfExtra_) + { + if ((features_.strictRoot_ || 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() +{ + // To preserve the old behaviour we cast size_t to int. + if (static_cast(nodes_.size()) > features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue()."); + Token token; + skipCommentTokens(token); + bool successful = true; + if (collectComments_ && !commentsBefore_.empty()) + { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_.clear(); + } + switch (token.type_) + { + case tokenObjectBegin: + successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenArrayBegin: + successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: + { + Value v(true); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenFalse: + { + Value v(false); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNull: + { + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNaN: + { + Value v(std::numeric_limits::quiet_NaN()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenPosInf: + { + Value v(std::numeric_limits::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNegInf: + { + Value v(-std::numeric_limits::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + 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); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // else, fall through ... + default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return addError("Syntax error: value, object or array expected.", token); + } + if (collectComments_) + { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + 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 continue + 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; +} + +JSONCPP_STRING OurReader::normalizeEOL(OurReader::Location begin, OurReader::Location end) +{ + JSONCPP_STRING normalized; + normalized.reserve(static_cast(end - begin)); + OurReader::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 +OurReader::addComment(Location begin, Location end, CommentPlacement placement) +{ + assert(collectComments_); + const JSONCPP_STRING& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) + { + assert(lastValue_ != 0); + lastValue_->setComment(normalized, placement); + } + else + { + commentsBefore_ += normalized; + } +} + +bool OurReader::readCStyleComment() +{ + while ((current_ + 1) < 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; + JSONCPP_STRING name; + Value init(objectValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + 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.clear(); + 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)) + { + JSONCPP_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); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + skipSpaces(); + if (current_ != end_ && *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); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + 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(static_cast(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); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeDouble(Token& token, Value& decoded) +{ + double value = 0; + const int bufferSize = 32; + int count; + ptrdiff_t const length = token.end_ - token.start_; + // Sanity check to avoid buffer overflow exploits. + if (length < 0) + { + return addError("Unable to parse token length", token); + } + size_t const ulength = static_cast(length); + // Avoid using a string constant for the format control string given to + // sscanf, as this can cause hard to debug crashes on OS X. See here for more + // info: + // + // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html + char format[] = "%lf"; + if (length <= bufferSize) + { + Char buffer[bufferSize + 1]; + memcpy(buffer, token.start_, ulength); + buffer[length] = 0; + fixNumericLocaleInput(buffer, buffer + length); + count = sscanf(buffer, format, &value); + } + else + { + JSONCPP_STRING buffer(token.start_, token.end_); + count = sscanf(buffer.c_str(), format, &value); + } + if (count != 1) + return addError("'" + JSONCPP_STRING(token.start_, token.end_) + + "' is not a number.", + token); + decoded = value; + return true; +} + +bool OurReader::decodeString(Token& token) +{ + JSONCPP_STRING decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) +{ + decoded.reserve(static_cast(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& ret_unicode) +{ + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", + token, + current); + int 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); + } + ret_unicode = static_cast(unicode); + return true; +} + +bool +OurReader::addError(const JSONCPP_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) +{ + size_t errorCount = 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 JSONCPP_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; +} + +JSONCPP_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; +} + +JSONCPP_STRING OurReader::getFormattedErrorMessages() const +{ + JSONCPP_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; +} + +std::vector OurReader::getStructuredErrors() const +{ + std::vector allErrors; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) + { + const ErrorInfo& error = *itError; + OurReader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) +{ + ptrdiff_t length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = end_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = 0; + errors_.push_back(info); + return true; +} + +bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) +{ + ptrdiff_t length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length + || extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool OurReader::good() const +{ + return !errors_.size(); +} + + +class OurCharReader : public CharReader +{ + bool const collectComments_; + OurReader reader_; +public: + OurCharReader( + bool collectComments, + OurFeatures const& features) + : collectComments_(collectComments) + , reader_(features) + {} + bool parse( + char const* beginDoc, char const* endDoc, + Value* root, JSONCPP_STRING* errs) JSONCPP_OVERRIDE + { + 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) + { + JSONCPP_STRING const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) + { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& CharReaderBuilder::operator[](JSONCPP_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)["stackLimit"] = 1000; + (*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, JSONCPP_ISTREAM& sin, + Value* root, JSONCPP_STRING* errs) +{ + JSONCPP_OSTRINGSTREAM ssin; + ssin << sin.rdbuf(); + JSONCPP_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); +} + +JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) +{ + CharReaderBuilder b; + JSONCPP_STRING errs; + bool ok = parseFromStream(b, sin, &root, &errs); + if (!ok) + { + fprintf(stderr, + "Error from reader: %s", + errs.c_str()); + throwRuntimeError(errs); + } + return sin; +} + +} // namespace Json diff --git a/src/external/lib_json/json_tool.h b/src/external/lib_json/json_tool.h new file mode 100644 index 0000000..fba08bc --- /dev/null +++ b/src/external/lib_json/json_tool.h @@ -0,0 +1,138 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// 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 + + +// Also support old flag NO_LOCALE_SUPPORT +#ifdef NO_LOCALE_SUPPORT +#define JSONCPP_NO_LOCALE_SUPPORT +#endif + +#ifndef JSONCPP_NO_LOCALE_SUPPORT +#include +#endif + +/* 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 +{ +static char getDecimalPoint() +{ +#ifdef JSONCPP_NO_LOCALE_SUPPORT + return '\0'; +#else + struct lconv* lc = localeconv(); + return lc ? *(lc->decimal_point) : '\0'; +#endif +} + +/// Converts a unicode code-point to UTF-8. +static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) +{ + JSONCPP_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; + } +} + +static inline void fixNumericLocaleInput(char* begin, char* end) +{ + char decimalPoint = getDecimalPoint(); + if (decimalPoint != '\0' && decimalPoint != '.') + { + while (begin < end) + { + if (*begin == '.') + { + *begin = decimalPoint; + } + ++begin; + } + } +} + +} // namespace Json { + +#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED diff --git a/src/external/lib_json/json_value.cpp b/src/external/lib_json/json_value.cpp new file mode 100644 index 0000000..3373973 --- /dev/null +++ b/src/external/lib_json/json_value.cpp @@ -0,0 +1,1905 @@ +// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors +// 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 +#define ALIGNAS(byte_alignment) +#endif +//static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; +//const unsigned char& kNullRef = kNull[0]; +//const Value& Value::null = reinterpret_cast(kNullRef); +//const Value& Value::nullRef = null; + +// static +Value const& Value::nullSingleton() +{ + static Value const nullStatic; + return nullStatic; +} + +// for backwards compatibility, we'll leave these global references around, but DO NOT +// use them in JSONCPP library code any more! +Value const& Value::null = Value::nullSingleton(); +Value const& Value::nullRef = Value::nullSingleton(); + +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) +{ + // The casts can lose precision, but we are looking only for + // an approximate range. Might fail on edge cases though. ~cdunn + //return d >= static_cast(min) && d <= static_cast(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 + static_cast(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(). + */ +#if JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) +{ + unsigned length = 0; + char const* valueDecoded; + decodePrefixedString(true, value, &length, &valueDecoded); + size_t const size = sizeof(unsigned) + length + 1U; + memset(value, 0, size); + free(value); +} +static inline void releaseStringValue(char* value, unsigned length) +{ + // length==0 => we allocated the strings memory + size_t size = (length==0) ? strlen(value) : length; + memset(value, 0, size); + free(value); +} +#else // !JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) +{ + free(value); +} +static inline void releaseStringValue(char* value, unsigned) +{ + free(value); +} +#endif // JSONCPP_USING_SECURE_MEMORY + +} // namespace Json + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ValueInternals... +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +#if !defined(JSON_IS_AMALGAMATION) + +#include "json_valueiterator.inl" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json +{ + +Exception::Exception(JSONCPP_STRING const& msg) + : msg_(msg) +{} +Exception::~Exception() JSONCPP_NOEXCEPT +{} +char const* Exception::what() const JSONCPP_NOEXCEPT +{ + return msg_.c_str(); +} +RuntimeError::RuntimeError(JSONCPP_STRING const& msg) + : Exception(msg) +{} +LogicError::LogicError(JSONCPP_STRING const& msg) + : Exception(msg) +{} +JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg) +{ + throw RuntimeError(msg); +} +JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg) +{ + throw LogicError(msg); +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CommentInfo +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +Value::CommentInfo::CommentInfo() : comment_(0) +{} + +Value::CommentInfo::~CommentInfo() +{ + if (comment_) + releaseStringValue(comment_, 0u); +} + +void Value::CommentInfo::setComment(const char* text, size_t len) +{ + if (comment_) + { + releaseStringValue(comment_, 0u); + 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_ = static_cast(other.cstr_ + ? (static_cast(other.storage_.policy_) == noDuplication + ? noDuplication : duplicate) + : static_cast(other.storage_.policy_)) & 3U; + storage_.length_ = other.storage_.length_; +} + +#if JSON_HAS_RVALUE_REFERENCES +Value::CZString::CZString(CZString&& other) + : cstr_(other.cstr_), index_(other.index_) +{ + other.cstr_ = NULL; +} +#endif + +Value::CZString::~CZString() +{ + if (cstr_ && storage_.policy_ == duplicate) + { + releaseStringValue(const_cast(cstr_), storage_.length_ + 1u); //+1 for null terminating character for sake of completeness but not actually necessary + } +} + +void Value::CZString::swap(CZString& other) +{ + std::swap(cstr_, other.cstr_); + std::swap(index_, other.index_); +} + +Value::CZString& Value::CZString::operator=(const CZString& other) +{ + cstr_ = other.cstr_; + index_ = other.index_; + return *this; +} + +#if JSON_HAS_RVALUE_REFERENCES +Value::CZString& Value::CZString::operator=(CZString&& other) +{ + cstr_ = other.cstr_; + index_ = other.index_; + other.cstr_ = NULL; + return *this; +} +#endif + +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); + JSON_ASSERT(this->cstr_ && other.cstr_); + 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; + JSON_ASSERT(this->cstr_ && other.cstr_); + 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) +{ + static char const emptyString[] = ""; + initBasic(vtype); + switch (vtype) + { + case nullValue: + break; + case intValue: + case uintValue: + value_.int_ = 0; + break; + case realValue: + value_.real_ = 0.0; + break; + case stringValue: + // allocated_ == false, so this is safe. + value_.string_ = const_cast(static_cast(emptyString)); + 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); + JSON_ASSERT_MESSAGE(value != NULL, "Null Value Passed to Value Constructor"); + 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 JSONCPP_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), start_(other.start_), limit_(other.limit_) +{ + 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_)); + } + } +} + +#if JSON_HAS_RVALUE_REFERENCES +// Move constructor +Value::Value(Value&& other) +{ + initBasic(nullValue); + swap(other); +} +#endif + +Value::~Value() +{ + switch (type_) + { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue: + if (allocated_) + releasePrefixedStringValue(value_.string_); + break; + case arrayValue: + case objectValue: + delete value_.map_; + break; + default: + JSON_ASSERT_UNREACHABLE; + } + delete[] comments_; + value_.uint_ = 0; +} + +Value& Value::operator=(Value other) +{ + swap(other); + 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::copyPayload(const Value& other) +{ + type_ = other.type_; + value_ = other.value_; + allocated_ = other.allocated_; +} + +void Value::swap(Value& other) +{ + swapPayload(other); + std::swap(comments_, other.comments_); + std::swap(start_, other.start_); + std::swap(limit_, other.limit_); +} + +void Value::copy(const Value& other) +{ + copyPayload(other); + comments_ = other.comments_; + start_ = other.start_; + limit_ = other.limit_; +} + +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); + JSON_ASSERT(this_str && other_str); + 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; + JSON_ASSERT(this_str && other_str); + 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; +} + +#if JSONCPP_USING_SECURE_MEMORY +unsigned Value::getCStringLength() 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_len; +} +#endif + +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; +} + +JSONCPP_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 JSONCPP_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) + // This can fail (silently?) if the value is bigger than MAX_FLOAT. + return static_cast(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().empty()) || + (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"); + start_ = 0; + limit_ = 0; + 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); + } + JSON_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, nullSingleton()); + 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 nullSingleton(); + CZString key(index); + ObjectValues::const_iterator it = value_.map_->find(key); + if (it == value_.map_->end()) + return nullSingleton(); + 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; + start_ = 0; + limit_ = 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, nullSingleton()); + 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, nullSingleton()); + 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 == &nullSingleton() ? 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 nullSingleton(); + return *found; +} +Value const& Value::operator[](JSONCPP_STRING const& key) const +{ + Value const* found = find(key.data(), key.data() + key.length()); + if (!found) return nullSingleton(); + return *found; +} + +Value& Value::operator[](const char* key) +{ + return resolveReference(key, key + strlen(key)); +} + +Value& Value::operator[](const JSONCPP_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 nullSingleton(); + return *found; +} +#endif + +Value& Value::append(const Value& value) +{ + return (*this)[size()] = value; +} + +#if JSON_HAS_RVALUE_REFERENCES +Value& Value::append(Value&& value) +{ + return (*this)[size()] = value; +} +#endif + +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(JSONCPP_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(JSONCPP_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 nullSingleton(); + Value removed; // null + removeMember(key, key + strlen(key), &removed); + return removed; // still null if removeMember() did nothing +} +Value Value::removeMember(const JSONCPP_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(JSONCPP_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(JSONCPP_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: +#if defined(JSON_HAS_INT64) + return value_.int_ >= minInt && value_.int_ <= maxInt; +#else + return true; +#endif + 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: +#if defined(JSON_HAS_INT64) + return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); +#else + return value_.int_ >= 0; +#endif + case uintValue: +#if defined(JSON_HAS_INT64) + return value_.uint_ <= maxUInt; +#else + return true; +#endif + 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 +{ + switch (type_) + { + case intValue: + case uintValue: + return true; + case realValue: +#if defined(JSON_HAS_INT64) + // 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_ >= double(minInt64) && value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_); +#else + return value_.real_ >= minInt && value_.real_ <= maxUInt && IsIntegral(value_.real_); +#endif // JSON_HAS_INT64 + default: + break; + } + return false; +} + +bool Value::isDouble() const +{ + return type_ == intValue || type_ == uintValue || type_ == realValue; +} + +bool Value::isNumeric() const +{ + return 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 JSONCPP_STRING& comment, CommentPlacement placement) +{ + setComment(comment.c_str(), comment.length(), placement); +} + +bool Value::hasComment(CommentPlacement placement) const +{ + return comments_ != 0 && comments_[placement].comment_ != 0; +} + +JSONCPP_STRING Value::getComment(CommentPlacement placement) const +{ + if (hasComment(placement)) + return comments_[placement].comment_; + return ""; +} + +void Value::setOffsetStart(ptrdiff_t start) +{ + start_ = start; +} + +void Value::setOffsetLimit(ptrdiff_t limit) +{ + limit_ = limit; +} + +ptrdiff_t Value::getOffsetStart() const +{ + return start_; +} + +ptrdiff_t Value::getOffsetLimit() const +{ + return limit_; +} + +JSONCPP_STRING Value::toStyledString() const +{ + StreamWriterBuilder builder; + JSONCPP_STRING out = this->hasComment(commentBefore) ? "\n" : ""; + out += Json::writeString(builder, *this); + out += "\n"; + return out; +} + +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 JSONCPP_STRING& key) + : key_(key.c_str()), index_(), kind_(kindKey) {} + +// class Path +// ////////////////////////////////////////////////////////////////// + +Path::Path(const JSONCPP_STRING& path, + const PathArgument& a1, + const PathArgument& a2, + const PathArgument& a3, + const PathArgument& a4, + const PathArgument& a5) +{ + InArgs in; + in.reserve(5); + 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 JSONCPP_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 == ']') + { + ++current; + } + else + { + const char* beginName = current; + while (current != end && !strchr("[.", *current)) + ++current; + args_.push_back(JSONCPP_STRING(beginName, current)); + } + } +} + +void Path::addPathInArg(const JSONCPP_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 JSONCPP_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... + return Value::null; + } + node = &((*node)[arg.index_]); + } + else if (arg.kind_ == PathArgument::kindKey) + { + if (!node->isObject()) + { + // Error: unable to resolve path (object value expected at position...) + return Value::null; + } + node = &((*node)[arg.key_]); + if (node == &Value::nullSingleton()) + { + // Error: unable to resolve path (object has no member named '' at + // position...) + return Value::null; + } + } + } + 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::nullSingleton()) + 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 diff --git a/src/external/lib_json/json_valueiterator.inl b/src/external/lib_json/json_valueiterator.inl new file mode 100644 index 0000000..5243bfe --- /dev/null +++ b/src/external/lib_json/json_valueiterator.inl @@ -0,0 +1,167 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// 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); +} + +JSONCPP_STRING ValueIteratorBase::name() const { + char const* keey; + char const* end; + keey = memberName(&end); + if (!keey) return JSONCPP_STRING(); + return JSONCPP_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(ValueIterator const& other) + : ValueIteratorBase(other) {} + +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) { + throwRuntimeError("ConstIterator to Iterator should never be allowed."); +} + +ValueIterator::ValueIterator(const ValueIterator& other) + : ValueIteratorBase(other) {} + +ValueIterator& ValueIterator::operator=(const SelfType& other) { + copy(other); + return *this; +} + +} // namespace Json diff --git a/src/external/lib_json/json_writer.cpp b/src/external/lib_json/json_writer.cpp new file mode 100644 index 0000000..6b5e68e --- /dev/null +++ b/src/external/lib_json/json_writer.cpp @@ -0,0 +1,1387 @@ +// Copyright 2011 Baptiste Lepilleur and The JsonCpp Authors +// 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 +#if !defined(isfinite) +#include +#define isfinite finite +#endif +#elif defined(_AIX) +#if !defined(isfinite) +#include +#define isfinite finite +#endif +#elif defined(__hpux) +#if !defined(isfinite) +#if defined(__ia64) && !defined(finite) +#define isfinite(x) ((sizeof(x) == sizeof(float) ? \ + _Isfinitef(x) : _IsFinite(x))) +#else +#include +#define isfinite finite +#endif +#endif +#else +#include +#if !(defined(__QNXNTO__)) // QNX already defines isfinite +#define isfinite std::isfinite +#endif +#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__) || defined(__QNXNTO__) +#define snprintf snprintf +#elif __cplusplus >= 201103L +#if !defined(__MINGW32__) && !defined(__CYGWIN__) +#define snprintf std::snprintf +#endif +#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; +} + +JSONCPP_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; +} + +JSONCPP_STRING valueToString(LargestUInt value) +{ + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + uintToString(value, current); + assert(current >= buffer); + return current; +} + +#if defined(JSON_HAS_INT64) + +JSONCPP_STRING valueToString(Int value) +{ + return valueToString(LargestInt(value)); +} + +JSONCPP_STRING valueToString(UInt value) +{ + return valueToString(LargestUInt(value)); +} + +#endif // # if defined(JSON_HAS_INT64) + +namespace +{ +JSONCPP_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[36]; + int len = -1; + char formatString[15]; + snprintf(formatString, sizeof(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); + fixNumericLocale(buffer, buffer + len); + // try to ensure we preserve the fact that this was given to us as a double on input + if (!strchr(buffer, '.') && !strchr(buffer, 'e')) + { + strcat(buffer, ".0"); + } + } + 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"); + } + } + assert(len >= 0); + return buffer; +} +} + +JSONCPP_STRING valueToString(double value) +{ + return valueToString(value, false, 17); +} + +JSONCPP_STRING valueToString(bool value) +{ + return value ? "true" : "false"; +} + +JSONCPP_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 JSONCPP_STRING("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to JSONCPP_STRING is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + JSONCPP_STRING::size_type maxsize = + strlen(value) * 2 + 3; // allescaped+quotes+NULL + JSONCPP_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 JSONCPP_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 JSONCPP_STRING("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to JSONCPP_STRING is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + JSONCPP_STRING::size_type maxsize = + length * 2 + 3; // allescaped+quotes+NULL + JSONCPP_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), dropNullPlaceholders_(false), + omitEndingLineFeed_(false) {} + +void FastWriter::enableYAMLCompatibility() +{ + yamlCompatiblityEnabled_ = true; +} + +void FastWriter::dropNullPlaceholders() +{ + dropNullPlaceholders_ = true; +} + +void FastWriter::omitEndingLineFeed() +{ + omitEndingLineFeed_ = true; +} + +JSONCPP_STRING FastWriter::write(const Value& root) +{ + document_.clear(); + writeValue(root); + if (!omitEndingLineFeed_) + document_ += "\n"; + return document_; +} + +void FastWriter::writeValue(const Value& value) +{ + switch (value.type()) + { + case nullValue: + if (!dropNullPlaceholders_) + 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_? No. + 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_ += '['; + ArrayIndex size = value.size(); + for (ArrayIndex 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 JSONCPP_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_() {} + +JSONCPP_STRING StyledWriter::write(const Value& root) +{ + document_.clear(); + addChildValues_ = false; + indentString_.clear(); + 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_? No. + 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 JSONCPP_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) +{ + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) + { + const Value& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) + { + if (hasCommentForValue(value[index])) + { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledWriter::pushValue(const JSONCPP_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 JSONCPP_STRING& value) +{ + writeIndent(); + document_ += value; +} + +void StyledWriter::indent() +{ + indentString_ += JSONCPP_STRING(indentSize_, ' '); +} + +void StyledWriter::unindent() +{ + assert(indentString_.size() >= indentSize_); + indentString_.resize(indentString_.size() - indentSize_); +} + +void StyledWriter::writeCommentBeforeValue(const Value& root) +{ + if (!root.hasComment(commentBefore)) + return; + document_ += "\n"; + writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) + { + document_ += *iter; + if (*iter == '\n' && + ((iter+1) != 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(JSONCPP_STRING indentation) + : document_(NULL), rightMargin_(74), indentation_(indentation), + addChildValues_() {} + +void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) +{ + document_ = &out; + addChildValues_ = false; + indentString_.clear(); + 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_? No. + 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 JSONCPP_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) +{ + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) + { + const Value& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) + { + if (hasCommentForValue(value[index])) + { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledStreamWriter::pushValue(const JSONCPP_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 JSONCPP_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 JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) + { + *document_ << *iter; + if (*iter == '\n' && + ((iter+1) != 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( + JSONCPP_STRING const& indentation, + CommentStyle::Enum cs, + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision); + int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE; +private: + void writeValue(Value const& value); + void writeArrayValue(Value const& value); + bool isMultineArray(Value const& value); + void pushValue(JSONCPP_STRING const& value); + void writeIndent(); + void writeWithIndent(JSONCPP_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_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + JSONCPP_STRING indentation_; + CommentStyle::Enum cs_; + JSONCPP_STRING colonSymbol_; + JSONCPP_STRING nullSymbol_; + JSONCPP_STRING endingLineFeedSymbol_; + bool addChildValues_ : 1; + bool indented_ : 1; + bool useSpecialFloats_ : 1; + unsigned int precision_; +}; +BuiltStyledStreamWriter::BuiltStyledStreamWriter( + JSONCPP_STRING const& indentation, + CommentStyle::Enum cs, + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_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, JSONCPP_OSTREAM* sout) +{ + sout_ = sout; + addChildValues_ = false; + indented_ = true; + indentString_.clear(); + 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_? No. + 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 (;;) + { + JSONCPP_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_ << ((!indentation_.empty()) ? ", " : ","); + *sout_ << childValues_[index]; + } + if (!indentation_.empty()) *sout_ << " "; + *sout_ << "]"; + } + } +} + +bool BuiltStyledStreamWriter::isMultineArray(Value const& value) +{ + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) + { + Value const& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) + { + if (hasCommentForValue(value[index])) + { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void BuiltStyledStreamWriter::pushValue(JSONCPP_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(JSONCPP_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 JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) + { + *sout_ << *iter; + if (*iter == '\n' && + ((iter+1) != 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 +{ + JSONCPP_STRING indentation = settings_["indentation"].asString(); + JSONCPP_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'"); + } + JSONCPP_STRING colonSymbol = " : "; + if (eyc) + { + colonSymbol = ": "; + } + else if (indentation.empty()) + { + colonSymbol = ":"; + } + JSONCPP_STRING nullSymbol = "null"; + if (dnp) + { + nullSymbol.clear(); + } + if (pre > 17) pre = 17; + JSONCPP_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) + { + JSONCPP_STRING const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) + { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& StreamWriterBuilder::operator[](JSONCPP_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] +} + +JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) +{ + JSONCPP_OSTRINGSTREAM sout; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout.str(); +} + +JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) +{ + StreamWriterBuilder builder; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout; +} + +} // namespace Json diff --git a/src/external/yaml/api.c b/src/external/yaml/api.c new file mode 100644 index 0000000..b1a8da0 --- /dev/null +++ b/src/external/yaml/api.c @@ -0,0 +1,1392 @@ + +#include "yaml_private.h" + +/* + * Get the library version. + */ + +YAML_DECLARE(const char *) +yaml_get_version_string(void) +{ + return YAML_VERSION_STRING; +} + +/* + * Get the library version numbers. + */ + +YAML_DECLARE(void) +yaml_get_version(int *major, int *minor, int *patch) +{ + *major = YAML_VERSION_MAJOR; + *minor = YAML_VERSION_MINOR; + *patch = YAML_VERSION_PATCH; +} + +/* + * Allocate a dynamic memory block. + */ + +YAML_DECLARE(void *) +yaml_malloc(size_t size) +{ + return malloc(size ? size : 1); +} + +/* + * Reallocate a dynamic memory block. + */ + +YAML_DECLARE(void *) +yaml_realloc(void *ptr, size_t size) +{ + return ptr ? realloc(ptr, size ? size : 1) : malloc(size ? size : 1); +} + +/* + * Free a dynamic memory block. + */ + +YAML_DECLARE(void) +yaml_free(void *ptr) +{ + if (ptr) free(ptr); +} + +/* + * Duplicate a string. + */ + +YAML_DECLARE(yaml_char_t *) +yaml_strdup(const yaml_char_t *str) +{ + if (!str) + return NULL; + + return (yaml_char_t *)strdup((char *)str); +} + +/* + * Extend a string. + */ + +YAML_DECLARE(int) +yaml_string_extend(yaml_char_t **start, + yaml_char_t **pointer, yaml_char_t **end) +{ + yaml_char_t *new_start = yaml_realloc(*start, (*end - *start)*2); + + if (!new_start) return 0; + + memset(new_start + (*end - *start), 0, *end - *start); + + *pointer = new_start + (*pointer - *start); + *end = new_start + (*end - *start)*2; + *start = new_start; + + return 1; +} + +/* + * Append a string B to a string A. + */ + +YAML_DECLARE(int) +yaml_string_join( + yaml_char_t **a_start, yaml_char_t **a_pointer, yaml_char_t **a_end, + yaml_char_t **b_start, yaml_char_t **b_pointer, yaml_char_t **b_end) +{ + if (*b_start == *b_pointer) + return 1; + + while (*a_end - *a_pointer <= *b_pointer - *b_start) { + if (!yaml_string_extend(a_start, a_pointer, a_end)) + return 0; + } + + memcpy(*a_pointer, *b_start, *b_pointer - *b_start); + *a_pointer += *b_pointer - *b_start; + + return 1; +} + +/* + * Extend a stack. + */ + +YAML_DECLARE(int) +yaml_stack_extend(void **start, void **top, void **end) +{ + void *new_start = yaml_realloc(*start, ((char *)*end - (char *)*start)*2); + + if (!new_start) return 0; + + *top = (char *)new_start + ((char *)*top - (char *)*start); + *end = (char *)new_start + ((char *)*end - (char *)*start)*2; + *start = new_start; + + return 1; +} + +/* + * Extend or move a queue. + */ + +YAML_DECLARE(int) +yaml_queue_extend(void **start, void **head, void **tail, void **end) +{ + /* Check if we need to resize the queue. */ + + if (*start == *head && *tail == *end) { + void *new_start = yaml_realloc(*start, + ((char *)*end - (char *)*start)*2); + + if (!new_start) return 0; + + *head = (char *)new_start + ((char *)*head - (char *)*start); + *tail = (char *)new_start + ((char *)*tail - (char *)*start); + *end = (char *)new_start + ((char *)*end - (char *)*start)*2; + *start = new_start; + } + + /* Check if we need to move the queue at the beginning of the buffer. */ + + if (*tail == *end) { + if (*head != *tail) { + memmove(*start, *head, (char *)*tail - (char *)*head); + } + *tail = (char *)*tail - (char *)*head + (char *)*start; + *head = *start; + } + + return 1; +} + + +/* + * Create a new parser object. + */ + +YAML_DECLARE(int) +yaml_parser_initialize(yaml_parser_t *parser) +{ + assert(parser); /* Non-NULL parser object expected. */ + + memset(parser, 0, sizeof(yaml_parser_t)); + if (!BUFFER_INIT(parser, parser->raw_buffer, INPUT_RAW_BUFFER_SIZE)) + goto error; + if (!BUFFER_INIT(parser, parser->buffer, INPUT_BUFFER_SIZE)) + goto error; + if (!QUEUE_INIT(parser, parser->tokens, INITIAL_QUEUE_SIZE)) + goto error; + if (!STACK_INIT(parser, parser->indents, INITIAL_STACK_SIZE)) + goto error; + if (!STACK_INIT(parser, parser->simple_keys, INITIAL_STACK_SIZE)) + goto error; + if (!STACK_INIT(parser, parser->states, INITIAL_STACK_SIZE)) + goto error; + if (!STACK_INIT(parser, parser->marks, INITIAL_STACK_SIZE)) + goto error; + if (!STACK_INIT(parser, parser->tag_directives, INITIAL_STACK_SIZE)) + goto error; + + return 1; + +error: + + BUFFER_DEL(parser, parser->raw_buffer); + BUFFER_DEL(parser, parser->buffer); + QUEUE_DEL(parser, parser->tokens); + STACK_DEL(parser, parser->indents); + STACK_DEL(parser, parser->simple_keys); + STACK_DEL(parser, parser->states); + STACK_DEL(parser, parser->marks); + STACK_DEL(parser, parser->tag_directives); + + return 0; +} + +/* + * Destroy a parser object. + */ + +YAML_DECLARE(void) +yaml_parser_delete(yaml_parser_t *parser) +{ + assert(parser); /* Non-NULL parser object expected. */ + + BUFFER_DEL(parser, parser->raw_buffer); + BUFFER_DEL(parser, parser->buffer); + while (!QUEUE_EMPTY(parser, parser->tokens)) { + yaml_token_delete(&DEQUEUE(parser, parser->tokens)); + } + QUEUE_DEL(parser, parser->tokens); + STACK_DEL(parser, parser->indents); + STACK_DEL(parser, parser->simple_keys); + STACK_DEL(parser, parser->states); + STACK_DEL(parser, parser->marks); + while (!STACK_EMPTY(parser, parser->tag_directives)) { + yaml_tag_directive_t tag_directive = POP(parser, parser->tag_directives); + yaml_free(tag_directive.handle); + yaml_free(tag_directive.prefix); + } + STACK_DEL(parser, parser->tag_directives); + + memset(parser, 0, sizeof(yaml_parser_t)); +} + +/* + * String read handler. + */ + +static int +yaml_string_read_handler(void *data, unsigned char *buffer, size_t size, + size_t *size_read) +{ + yaml_parser_t *parser = data; + + if (parser->input.string.current == parser->input.string.end) { + *size_read = 0; + return 1; + } + + if (size > (size_t)(parser->input.string.end + - parser->input.string.current)) { + size = parser->input.string.end - parser->input.string.current; + } + + memcpy(buffer, parser->input.string.current, size); + parser->input.string.current += size; + *size_read = size; + return 1; +} + +/* + * File read handler. + */ + +static int +yaml_file_read_handler(void *data, unsigned char *buffer, size_t size, + size_t *size_read) +{ + yaml_parser_t *parser = data; + + *size_read = fread(buffer, 1, size, parser->input.file); + return !ferror(parser->input.file); +} + +/* + * Set a string input. + */ + +YAML_DECLARE(void) +yaml_parser_set_input_string(yaml_parser_t *parser, + const unsigned char *input, size_t size) +{ + assert(parser); /* Non-NULL parser object expected. */ + assert(!parser->read_handler); /* You can set the source only once. */ + assert(input); /* Non-NULL input string expected. */ + + parser->read_handler = yaml_string_read_handler; + parser->read_handler_data = parser; + + parser->input.string.start = input; + parser->input.string.current = input; + parser->input.string.end = input+size; +} + +/* + * Set a file input. + */ + +YAML_DECLARE(void) +yaml_parser_set_input_file(yaml_parser_t *parser, FILE *file) +{ + assert(parser); /* Non-NULL parser object expected. */ + assert(!parser->read_handler); /* You can set the source only once. */ + assert(file); /* Non-NULL file object expected. */ + + parser->read_handler = yaml_file_read_handler; + parser->read_handler_data = parser; + + parser->input.file = file; +} + +/* + * Set a generic input. + */ + +YAML_DECLARE(void) +yaml_parser_set_input(yaml_parser_t *parser, + yaml_read_handler_t *handler, void *data) +{ + assert(parser); /* Non-NULL parser object expected. */ + assert(!parser->read_handler); /* You can set the source only once. */ + assert(handler); /* Non-NULL read handler expected. */ + + parser->read_handler = handler; + parser->read_handler_data = data; +} + +/* + * Set the source encoding. + */ + +YAML_DECLARE(void) +yaml_parser_set_encoding(yaml_parser_t *parser, yaml_encoding_t encoding) +{ + assert(parser); /* Non-NULL parser object expected. */ + assert(!parser->encoding); /* Encoding is already set or detected. */ + + parser->encoding = encoding; +} + +/* + * Create a new emitter object. + */ + +YAML_DECLARE(int) +yaml_emitter_initialize(yaml_emitter_t *emitter) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + memset(emitter, 0, sizeof(yaml_emitter_t)); + if (!BUFFER_INIT(emitter, emitter->buffer, OUTPUT_BUFFER_SIZE)) + goto error; + if (!BUFFER_INIT(emitter, emitter->raw_buffer, OUTPUT_RAW_BUFFER_SIZE)) + goto error; + if (!STACK_INIT(emitter, emitter->states, INITIAL_STACK_SIZE)) + goto error; + if (!QUEUE_INIT(emitter, emitter->events, INITIAL_QUEUE_SIZE)) + goto error; + if (!STACK_INIT(emitter, emitter->indents, INITIAL_STACK_SIZE)) + goto error; + if (!STACK_INIT(emitter, emitter->tag_directives, INITIAL_STACK_SIZE)) + goto error; + + return 1; + +error: + + BUFFER_DEL(emitter, emitter->buffer); + BUFFER_DEL(emitter, emitter->raw_buffer); + STACK_DEL(emitter, emitter->states); + QUEUE_DEL(emitter, emitter->events); + STACK_DEL(emitter, emitter->indents); + STACK_DEL(emitter, emitter->tag_directives); + + return 0; +} + +/* + * Destroy an emitter object. + */ + +YAML_DECLARE(void) +yaml_emitter_delete(yaml_emitter_t *emitter) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + BUFFER_DEL(emitter, emitter->buffer); + BUFFER_DEL(emitter, emitter->raw_buffer); + STACK_DEL(emitter, emitter->states); + while (!QUEUE_EMPTY(emitter, emitter->events)) { + yaml_event_delete(&DEQUEUE(emitter, emitter->events)); + } + QUEUE_DEL(emitter, emitter->events); + STACK_DEL(emitter, emitter->indents); + while (!STACK_EMPTY(empty, emitter->tag_directives)) { + yaml_tag_directive_t tag_directive = POP(emitter, emitter->tag_directives); + yaml_free(tag_directive.handle); + yaml_free(tag_directive.prefix); + } + STACK_DEL(emitter, emitter->tag_directives); + yaml_free(emitter->anchors); + + memset(emitter, 0, sizeof(yaml_emitter_t)); +} + +/* + * String write handler. + */ + +static int +yaml_string_write_handler(void *data, unsigned char *buffer, size_t size) +{ + yaml_emitter_t *emitter = data; + + if (emitter->output.string.size - *emitter->output.string.size_written + < size) { + memcpy(emitter->output.string.buffer + + *emitter->output.string.size_written, + buffer, + emitter->output.string.size + - *emitter->output.string.size_written); + *emitter->output.string.size_written = emitter->output.string.size; + return 0; + } + + memcpy(emitter->output.string.buffer + + *emitter->output.string.size_written, buffer, size); + *emitter->output.string.size_written += size; + return 1; +} + +/* + * File write handler. + */ + +static int +yaml_file_write_handler(void *data, unsigned char *buffer, size_t size) +{ + yaml_emitter_t *emitter = data; + + return (fwrite(buffer, 1, size, emitter->output.file) == size); +} +/* + * Set a string output. + */ + +YAML_DECLARE(void) +yaml_emitter_set_output_string(yaml_emitter_t *emitter, + unsigned char *output, size_t size, size_t *size_written) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + assert(!emitter->write_handler); /* You can set the output only once. */ + assert(output); /* Non-NULL output string expected. */ + + emitter->write_handler = yaml_string_write_handler; + emitter->write_handler_data = emitter; + + emitter->output.string.buffer = output; + emitter->output.string.size = size; + emitter->output.string.size_written = size_written; + *size_written = 0; +} + +/* + * Set a file output. + */ + +YAML_DECLARE(void) +yaml_emitter_set_output_file(yaml_emitter_t *emitter, FILE *file) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + assert(!emitter->write_handler); /* You can set the output only once. */ + assert(file); /* Non-NULL file object expected. */ + + emitter->write_handler = yaml_file_write_handler; + emitter->write_handler_data = emitter; + + emitter->output.file = file; +} + +/* + * Set a generic output handler. + */ + +YAML_DECLARE(void) +yaml_emitter_set_output(yaml_emitter_t *emitter, + yaml_write_handler_t *handler, void *data) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + assert(!emitter->write_handler); /* You can set the output only once. */ + assert(handler); /* Non-NULL handler object expected. */ + + emitter->write_handler = handler; + emitter->write_handler_data = data; +} + +/* + * Set the output encoding. + */ + +YAML_DECLARE(void) +yaml_emitter_set_encoding(yaml_emitter_t *emitter, yaml_encoding_t encoding) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + assert(!emitter->encoding); /* You can set encoding only once. */ + + emitter->encoding = encoding; +} + +/* + * Set the canonical output style. + */ + +YAML_DECLARE(void) +yaml_emitter_set_canonical(yaml_emitter_t *emitter, int canonical) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + emitter->canonical = (canonical != 0); +} + +/* + * Set the indentation increment. + */ + +YAML_DECLARE(void) +yaml_emitter_set_indent(yaml_emitter_t *emitter, int indent) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + emitter->best_indent = (1 < indent && indent < 10) ? indent : 2; +} + +/* + * Set the preferred line width. + */ + +YAML_DECLARE(void) +yaml_emitter_set_width(yaml_emitter_t *emitter, int width) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + emitter->best_width = (width >= 0) ? width : -1; +} + +/* + * Set if unescaped non-ASCII characters are allowed. + */ + +YAML_DECLARE(void) +yaml_emitter_set_unicode(yaml_emitter_t *emitter, int unicode) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + emitter->unicode = (unicode != 0); +} + +/* + * Set the preferred line break character. + */ + +YAML_DECLARE(void) +yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break) +{ + assert(emitter); /* Non-NULL emitter object expected. */ + + emitter->line_break = line_break; +} + +/* + * Destroy a token object. + */ + +YAML_DECLARE(void) +yaml_token_delete(yaml_token_t *token) +{ + assert(token); /* Non-NULL token object expected. */ + + switch (token->type) + { + case YAML_TAG_DIRECTIVE_TOKEN: + yaml_free(token->data.tag_directive.handle); + yaml_free(token->data.tag_directive.prefix); + break; + + case YAML_ALIAS_TOKEN: + yaml_free(token->data.alias.value); + break; + + case YAML_ANCHOR_TOKEN: + yaml_free(token->data.anchor.value); + break; + + case YAML_TAG_TOKEN: + yaml_free(token->data.tag.handle); + yaml_free(token->data.tag.suffix); + break; + + case YAML_SCALAR_TOKEN: + yaml_free(token->data.scalar.value); + break; + + default: + break; + } + + memset(token, 0, sizeof(yaml_token_t)); +} + +/* + * Check if a string is a valid UTF-8 sequence. + * + * Check 'reader.c' for more details on UTF-8 encoding. + */ + +static int +yaml_check_utf8(yaml_char_t *start, size_t length) +{ + yaml_char_t *end = start+length; + yaml_char_t *pointer = start; + + while (pointer < end) { + unsigned char octet; + unsigned int width; + unsigned int value; + size_t k; + + octet = pointer[0]; + width = (octet & 0x80) == 0x00 ? 1 : + (octet & 0xE0) == 0xC0 ? 2 : + (octet & 0xF0) == 0xE0 ? 3 : + (octet & 0xF8) == 0xF0 ? 4 : 0; + value = (octet & 0x80) == 0x00 ? octet & 0x7F : + (octet & 0xE0) == 0xC0 ? octet & 0x1F : + (octet & 0xF0) == 0xE0 ? octet & 0x0F : + (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; + if (!width) return 0; + if (pointer+width > end) return 0; + for (k = 1; k < width; k ++) { + octet = pointer[k]; + if ((octet & 0xC0) != 0x80) return 0; + value = (value << 6) + (octet & 0x3F); + } + if (!((width == 1) || + (width == 2 && value >= 0x80) || + (width == 3 && value >= 0x800) || + (width == 4 && value >= 0x10000))) return 0; + + pointer += width; + } + + return 1; +} + +/* + * Create STREAM-START. + */ + +YAML_DECLARE(int) +yaml_stream_start_event_initialize(yaml_event_t *event, + yaml_encoding_t encoding) +{ + yaml_mark_t mark = { 0, 0, 0 }; + + assert(event); /* Non-NULL event object is expected. */ + + STREAM_START_EVENT_INIT(*event, encoding, mark, mark); + + return 1; +} + +/* + * Create STREAM-END. + */ + +YAML_DECLARE(int) +yaml_stream_end_event_initialize(yaml_event_t *event) +{ + yaml_mark_t mark = { 0, 0, 0 }; + + assert(event); /* Non-NULL event object is expected. */ + + STREAM_END_EVENT_INIT(*event, mark, mark); + + return 1; +} + +/* + * Create DOCUMENT-START. + */ + +YAML_DECLARE(int) +yaml_document_start_event_initialize(yaml_event_t *event, + yaml_version_directive_t *version_directive, + yaml_tag_directive_t *tag_directives_start, + yaml_tag_directive_t *tag_directives_end, + int implicit) +{ + struct { + yaml_error_type_t error; + } context; + yaml_mark_t mark = { 0, 0, 0 }; + yaml_version_directive_t *version_directive_copy = NULL; + struct { + yaml_tag_directive_t *start; + yaml_tag_directive_t *end; + yaml_tag_directive_t *top; + } tag_directives_copy = { NULL, NULL, NULL }; + yaml_tag_directive_t value = { NULL, NULL }; + + assert(event); /* Non-NULL event object is expected. */ + assert((tag_directives_start && tag_directives_end) || + (tag_directives_start == tag_directives_end)); + /* Valid tag directives are expected. */ + + if (version_directive) { + version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t)); + if (!version_directive_copy) goto error; + version_directive_copy->major = version_directive->major; + version_directive_copy->minor = version_directive->minor; + } + + if (tag_directives_start != tag_directives_end) { + yaml_tag_directive_t *tag_directive; + if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE)) + goto error; + for (tag_directive = tag_directives_start; + tag_directive != tag_directives_end; tag_directive ++) { + assert(tag_directive->handle); + assert(tag_directive->prefix); + if (!yaml_check_utf8(tag_directive->handle, + strlen((char *)tag_directive->handle))) + goto error; + if (!yaml_check_utf8(tag_directive->prefix, + strlen((char *)tag_directive->prefix))) + goto error; + value.handle = yaml_strdup(tag_directive->handle); + value.prefix = yaml_strdup(tag_directive->prefix); + if (!value.handle || !value.prefix) goto error; + if (!PUSH(&context, tag_directives_copy, value)) + goto error; + value.handle = NULL; + value.prefix = NULL; + } + } + + DOCUMENT_START_EVENT_INIT(*event, version_directive_copy, + tag_directives_copy.start, tag_directives_copy.top, + implicit, mark, mark); + + return 1; + +error: + yaml_free(version_directive_copy); + while (!STACK_EMPTY(context, tag_directives_copy)) { + yaml_tag_directive_t value = POP(context, tag_directives_copy); + yaml_free(value.handle); + yaml_free(value.prefix); + } + STACK_DEL(context, tag_directives_copy); + yaml_free(value.handle); + yaml_free(value.prefix); + + return 0; +} + +/* + * Create DOCUMENT-END. + */ + +YAML_DECLARE(int) +yaml_document_end_event_initialize(yaml_event_t *event, int implicit) +{ + yaml_mark_t mark = { 0, 0, 0 }; + + assert(event); /* Non-NULL emitter object is expected. */ + + DOCUMENT_END_EVENT_INIT(*event, implicit, mark, mark); + + return 1; +} + +/* + * Create ALIAS. + */ + +YAML_DECLARE(int) +yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor) +{ + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *anchor_copy = NULL; + + assert(event); /* Non-NULL event object is expected. */ + assert(anchor); /* Non-NULL anchor is expected. */ + + if (!yaml_check_utf8(anchor, strlen((char *)anchor))) return 0; + + anchor_copy = yaml_strdup(anchor); + if (!anchor_copy) + return 0; + + ALIAS_EVENT_INIT(*event, anchor_copy, mark, mark); + + return 1; +} + +/* + * Create SCALAR. + */ + +YAML_DECLARE(int) +yaml_scalar_event_initialize(yaml_event_t *event, + yaml_char_t *anchor, yaml_char_t *tag, + yaml_char_t *value, int length, + int plain_implicit, int quoted_implicit, + yaml_scalar_style_t style) +{ + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *anchor_copy = NULL; + yaml_char_t *tag_copy = NULL; + yaml_char_t *value_copy = NULL; + + assert(event); /* Non-NULL event object is expected. */ + assert(value); /* Non-NULL anchor is expected. */ + + if (anchor) { + if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error; + anchor_copy = yaml_strdup(anchor); + if (!anchor_copy) goto error; + } + + if (tag) { + if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; + tag_copy = yaml_strdup(tag); + if (!tag_copy) goto error; + } + + if (length < 0) { + length = strlen((char *)value); + } + + if (!yaml_check_utf8(value, length)) goto error; + value_copy = yaml_malloc(length+1); + if (!value_copy) goto error; + memcpy(value_copy, value, length); + value_copy[length] = '\0'; + + SCALAR_EVENT_INIT(*event, anchor_copy, tag_copy, value_copy, length, + plain_implicit, quoted_implicit, style, mark, mark); + + return 1; + +error: + yaml_free(anchor_copy); + yaml_free(tag_copy); + yaml_free(value_copy); + + return 0; +} + +/* + * Create SEQUENCE-START. + */ + +YAML_DECLARE(int) +yaml_sequence_start_event_initialize(yaml_event_t *event, + yaml_char_t *anchor, yaml_char_t *tag, int implicit, + yaml_sequence_style_t style) +{ + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *anchor_copy = NULL; + yaml_char_t *tag_copy = NULL; + + assert(event); /* Non-NULL event object is expected. */ + + if (anchor) { + if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error; + anchor_copy = yaml_strdup(anchor); + if (!anchor_copy) goto error; + } + + if (tag) { + if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; + tag_copy = yaml_strdup(tag); + if (!tag_copy) goto error; + } + + SEQUENCE_START_EVENT_INIT(*event, anchor_copy, tag_copy, + implicit, style, mark, mark); + + return 1; + +error: + yaml_free(anchor_copy); + yaml_free(tag_copy); + + return 0; +} + +/* + * Create SEQUENCE-END. + */ + +YAML_DECLARE(int) +yaml_sequence_end_event_initialize(yaml_event_t *event) +{ + yaml_mark_t mark = { 0, 0, 0 }; + + assert(event); /* Non-NULL event object is expected. */ + + SEQUENCE_END_EVENT_INIT(*event, mark, mark); + + return 1; +} + +/* + * Create MAPPING-START. + */ + +YAML_DECLARE(int) +yaml_mapping_start_event_initialize(yaml_event_t *event, + yaml_char_t *anchor, yaml_char_t *tag, int implicit, + yaml_mapping_style_t style) +{ + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *anchor_copy = NULL; + yaml_char_t *tag_copy = NULL; + + assert(event); /* Non-NULL event object is expected. */ + + if (anchor) { + if (!yaml_check_utf8(anchor, strlen((char *)anchor))) goto error; + anchor_copy = yaml_strdup(anchor); + if (!anchor_copy) goto error; + } + + if (tag) { + if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; + tag_copy = yaml_strdup(tag); + if (!tag_copy) goto error; + } + + MAPPING_START_EVENT_INIT(*event, anchor_copy, tag_copy, + implicit, style, mark, mark); + + return 1; + +error: + yaml_free(anchor_copy); + yaml_free(tag_copy); + + return 0; +} + +/* + * Create MAPPING-END. + */ + +YAML_DECLARE(int) +yaml_mapping_end_event_initialize(yaml_event_t *event) +{ + yaml_mark_t mark = { 0, 0, 0 }; + + assert(event); /* Non-NULL event object is expected. */ + + MAPPING_END_EVENT_INIT(*event, mark, mark); + + return 1; +} + +/* + * Destroy an event object. + */ + +YAML_DECLARE(void) +yaml_event_delete(yaml_event_t *event) +{ + yaml_tag_directive_t *tag_directive; + + assert(event); /* Non-NULL event object expected. */ + + switch (event->type) + { + case YAML_DOCUMENT_START_EVENT: + yaml_free(event->data.document_start.version_directive); + for (tag_directive = event->data.document_start.tag_directives.start; + tag_directive != event->data.document_start.tag_directives.end; + tag_directive++) { + yaml_free(tag_directive->handle); + yaml_free(tag_directive->prefix); + } + yaml_free(event->data.document_start.tag_directives.start); + break; + + case YAML_ALIAS_EVENT: + yaml_free(event->data.alias.anchor); + break; + + case YAML_SCALAR_EVENT: + yaml_free(event->data.scalar.anchor); + yaml_free(event->data.scalar.tag); + yaml_free(event->data.scalar.value); + break; + + case YAML_SEQUENCE_START_EVENT: + yaml_free(event->data.sequence_start.anchor); + yaml_free(event->data.sequence_start.tag); + break; + + case YAML_MAPPING_START_EVENT: + yaml_free(event->data.mapping_start.anchor); + yaml_free(event->data.mapping_start.tag); + break; + + default: + break; + } + + memset(event, 0, sizeof(yaml_event_t)); +} + +/* + * Create a document object. + */ + +YAML_DECLARE(int) +yaml_document_initialize(yaml_document_t *document, + yaml_version_directive_t *version_directive, + yaml_tag_directive_t *tag_directives_start, + yaml_tag_directive_t *tag_directives_end, + int start_implicit, int end_implicit) +{ + struct { + yaml_error_type_t error; + } context; + struct { + yaml_node_t *start; + yaml_node_t *end; + yaml_node_t *top; + } nodes = { NULL, NULL, NULL }; + yaml_version_directive_t *version_directive_copy = NULL; + struct { + yaml_tag_directive_t *start; + yaml_tag_directive_t *end; + yaml_tag_directive_t *top; + } tag_directives_copy = { NULL, NULL, NULL }; + yaml_tag_directive_t value = { NULL, NULL }; + yaml_mark_t mark = { 0, 0, 0 }; + + assert(document); /* Non-NULL document object is expected. */ + assert((tag_directives_start && tag_directives_end) || + (tag_directives_start == tag_directives_end)); + /* Valid tag directives are expected. */ + + if (!STACK_INIT(&context, nodes, INITIAL_STACK_SIZE)) goto error; + + if (version_directive) { + version_directive_copy = yaml_malloc(sizeof(yaml_version_directive_t)); + if (!version_directive_copy) goto error; + version_directive_copy->major = version_directive->major; + version_directive_copy->minor = version_directive->minor; + } + + if (tag_directives_start != tag_directives_end) { + yaml_tag_directive_t *tag_directive; + if (!STACK_INIT(&context, tag_directives_copy, INITIAL_STACK_SIZE)) + goto error; + for (tag_directive = tag_directives_start; + tag_directive != tag_directives_end; tag_directive ++) { + assert(tag_directive->handle); + assert(tag_directive->prefix); + if (!yaml_check_utf8(tag_directive->handle, + strlen((char *)tag_directive->handle))) + goto error; + if (!yaml_check_utf8(tag_directive->prefix, + strlen((char *)tag_directive->prefix))) + goto error; + value.handle = yaml_strdup(tag_directive->handle); + value.prefix = yaml_strdup(tag_directive->prefix); + if (!value.handle || !value.prefix) goto error; + if (!PUSH(&context, tag_directives_copy, value)) + goto error; + value.handle = NULL; + value.prefix = NULL; + } + } + + DOCUMENT_INIT(*document, nodes.start, nodes.end, version_directive_copy, + tag_directives_copy.start, tag_directives_copy.top, + start_implicit, end_implicit, mark, mark); + + return 1; + +error: + STACK_DEL(&context, nodes); + yaml_free(version_directive_copy); + while (!STACK_EMPTY(&context, tag_directives_copy)) { + yaml_tag_directive_t value = POP(&context, tag_directives_copy); + yaml_free(value.handle); + yaml_free(value.prefix); + } + STACK_DEL(&context, tag_directives_copy); + yaml_free(value.handle); + yaml_free(value.prefix); + + return 0; +} + +/* + * Destroy a document object. + */ + +YAML_DECLARE(void) +yaml_document_delete(yaml_document_t *document) +{ + struct { + yaml_error_type_t error; + } context; + yaml_tag_directive_t *tag_directive; + + context.error = YAML_NO_ERROR; /* Eliminate a compliler warning. */ + + assert(document); /* Non-NULL document object is expected. */ + + while (!STACK_EMPTY(&context, document->nodes)) { + yaml_node_t node = POP(&context, document->nodes); + yaml_free(node.tag); + switch (node.type) { + case YAML_SCALAR_NODE: + yaml_free(node.data.scalar.value); + break; + case YAML_SEQUENCE_NODE: + STACK_DEL(&context, node.data.sequence.items); + break; + case YAML_MAPPING_NODE: + STACK_DEL(&context, node.data.mapping.pairs); + break; + default: + assert(0); /* Should not happen. */ + } + } + STACK_DEL(&context, document->nodes); + + yaml_free(document->version_directive); + for (tag_directive = document->tag_directives.start; + tag_directive != document->tag_directives.end; + tag_directive++) { + yaml_free(tag_directive->handle); + yaml_free(tag_directive->prefix); + } + yaml_free(document->tag_directives.start); + + memset(document, 0, sizeof(yaml_document_t)); +} + +/** + * Get a document node. + */ + +YAML_DECLARE(yaml_node_t *) +yaml_document_get_node(yaml_document_t *document, int index) +{ + assert(document); /* Non-NULL document object is expected. */ + + if (index > 0 && document->nodes.start + index <= document->nodes.top) { + return document->nodes.start + index - 1; + } + return NULL; +} + +/** + * Get the root object. + */ + +YAML_DECLARE(yaml_node_t *) +yaml_document_get_root_node(yaml_document_t *document) +{ + assert(document); /* Non-NULL document object is expected. */ + + if (document->nodes.top != document->nodes.start) { + return document->nodes.start; + } + return NULL; +} + +/* + * Add a scalar node to a document. + */ + +YAML_DECLARE(int) +yaml_document_add_scalar(yaml_document_t *document, + yaml_char_t *tag, yaml_char_t *value, int length, + yaml_scalar_style_t style) +{ + struct { + yaml_error_type_t error; + } context; + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *tag_copy = NULL; + yaml_char_t *value_copy = NULL; + yaml_node_t node; + + assert(document); /* Non-NULL document object is expected. */ + assert(value); /* Non-NULL value is expected. */ + + if (!tag) { + tag = (yaml_char_t *)YAML_DEFAULT_SCALAR_TAG; + } + + if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; + tag_copy = yaml_strdup(tag); + if (!tag_copy) goto error; + + if (length < 0) { + length = strlen((char *)value); + } + + if (!yaml_check_utf8(value, length)) goto error; + value_copy = yaml_malloc(length+1); + if (!value_copy) goto error; + memcpy(value_copy, value, length); + value_copy[length] = '\0'; + + SCALAR_NODE_INIT(node, tag_copy, value_copy, length, style, mark, mark); + if (!PUSH(&context, document->nodes, node)) goto error; + + return document->nodes.top - document->nodes.start; + +error: + yaml_free(tag_copy); + yaml_free(value_copy); + + return 0; +} + +/* + * Add a sequence node to a document. + */ + +YAML_DECLARE(int) +yaml_document_add_sequence(yaml_document_t *document, + yaml_char_t *tag, yaml_sequence_style_t style) +{ + struct { + yaml_error_type_t error; + } context; + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *tag_copy = NULL; + struct { + yaml_node_item_t *start; + yaml_node_item_t *end; + yaml_node_item_t *top; + } items = { NULL, NULL, NULL }; + yaml_node_t node; + + assert(document); /* Non-NULL document object is expected. */ + + if (!tag) { + tag = (yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG; + } + + if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; + tag_copy = yaml_strdup(tag); + if (!tag_copy) goto error; + + if (!STACK_INIT(&context, items, INITIAL_STACK_SIZE)) goto error; + + SEQUENCE_NODE_INIT(node, tag_copy, items.start, items.end, + style, mark, mark); + if (!PUSH(&context, document->nodes, node)) goto error; + + return document->nodes.top - document->nodes.start; + +error: + STACK_DEL(&context, items); + yaml_free(tag_copy); + + return 0; +} + +/* + * Add a mapping node to a document. + */ + +YAML_DECLARE(int) +yaml_document_add_mapping(yaml_document_t *document, + yaml_char_t *tag, yaml_mapping_style_t style) +{ + struct { + yaml_error_type_t error; + } context; + yaml_mark_t mark = { 0, 0, 0 }; + yaml_char_t *tag_copy = NULL; + struct { + yaml_node_pair_t *start; + yaml_node_pair_t *end; + yaml_node_pair_t *top; + } pairs = { NULL, NULL, NULL }; + yaml_node_t node; + + assert(document); /* Non-NULL document object is expected. */ + + if (!tag) { + tag = (yaml_char_t *)YAML_DEFAULT_MAPPING_TAG; + } + + if (!yaml_check_utf8(tag, strlen((char *)tag))) goto error; + tag_copy = yaml_strdup(tag); + if (!tag_copy) goto error; + + if (!STACK_INIT(&context, pairs, INITIAL_STACK_SIZE)) goto error; + + MAPPING_NODE_INIT(node, tag_copy, pairs.start, pairs.end, + style, mark, mark); + if (!PUSH(&context, document->nodes, node)) goto error; + + return document->nodes.top - document->nodes.start; + +error: + STACK_DEL(&context, pairs); + yaml_free(tag_copy); + + return 0; +} + +/* + * Append an item to a sequence node. + */ + +YAML_DECLARE(int) +yaml_document_append_sequence_item(yaml_document_t *document, + int sequence, int item) +{ + struct { + yaml_error_type_t error; + } context; + + assert(document); /* Non-NULL document is required. */ + assert(sequence > 0 + && document->nodes.start + sequence <= document->nodes.top); + /* Valid sequence id is required. */ + assert(document->nodes.start[sequence-1].type == YAML_SEQUENCE_NODE); + /* A sequence node is required. */ + assert(item > 0 && document->nodes.start + item <= document->nodes.top); + /* Valid item id is required. */ + + if (!PUSH(&context, + document->nodes.start[sequence-1].data.sequence.items, item)) + return 0; + + return 1; +} + +/* + * Append a pair of a key and a value to a mapping node. + */ + +YAML_DECLARE(int) +yaml_document_append_mapping_pair(yaml_document_t *document, + int mapping, int key, int value) +{ + struct { + yaml_error_type_t error; + } context; + + yaml_node_pair_t pair; + + assert(document); /* Non-NULL document is required. */ + assert(mapping > 0 + && document->nodes.start + mapping <= document->nodes.top); + /* Valid mapping id is required. */ + assert(document->nodes.start[mapping-1].type == YAML_MAPPING_NODE); + /* A mapping node is required. */ + assert(key > 0 && document->nodes.start + key <= document->nodes.top); + /* Valid key id is required. */ + assert(value > 0 && document->nodes.start + value <= document->nodes.top); + /* Valid value id is required. */ + + pair.key = key; + pair.value = value; + + if (!PUSH(&context, + document->nodes.start[mapping-1].data.mapping.pairs, pair)) + return 0; + + return 1; +} + + diff --git a/src/external/yaml/dumper.c b/src/external/yaml/dumper.c new file mode 100644 index 0000000..203c6a7 --- /dev/null +++ b/src/external/yaml/dumper.c @@ -0,0 +1,394 @@ + +#include "yaml_private.h" + +/* + * API functions. + */ + +YAML_DECLARE(int) +yaml_emitter_open(yaml_emitter_t *emitter); + +YAML_DECLARE(int) +yaml_emitter_close(yaml_emitter_t *emitter); + +YAML_DECLARE(int) +yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document); + +/* + * Clean up functions. + */ + +static void +yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter); + +/* + * Anchor functions. + */ + +static void +yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index); + +static yaml_char_t * +yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id); + + +/* + * Serialize functions. + */ + +static int +yaml_emitter_dump_node(yaml_emitter_t *emitter, int index); + +static int +yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor); + +static int +yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node, + yaml_char_t *anchor); + +static int +yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node, + yaml_char_t *anchor); + +static int +yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node, + yaml_char_t *anchor); + +/* + * Issue a STREAM-START event. + */ + +YAML_DECLARE(int) +yaml_emitter_open(yaml_emitter_t *emitter) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + assert(emitter); /* Non-NULL emitter object is required. */ + assert(!emitter->opened); /* Emitter should not be opened yet. */ + + STREAM_START_EVENT_INIT(event, YAML_ANY_ENCODING, mark, mark); + + if (!yaml_emitter_emit(emitter, &event)) { + return 0; + } + + emitter->opened = 1; + + return 1; +} + +/* + * Issue a STREAM-END event. + */ + +YAML_DECLARE(int) +yaml_emitter_close(yaml_emitter_t *emitter) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + assert(emitter); /* Non-NULL emitter object is required. */ + assert(emitter->opened); /* Emitter should be opened. */ + + if (emitter->closed) return 1; + + STREAM_END_EVENT_INIT(event, mark, mark); + + if (!yaml_emitter_emit(emitter, &event)) { + return 0; + } + + emitter->closed = 1; + + return 1; +} + +/* + * Dump a YAML document. + */ + +YAML_DECLARE(int) +yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + assert(emitter); /* Non-NULL emitter object is required. */ + assert(document); /* Non-NULL emitter object is expected. */ + + emitter->document = document; + + if (!emitter->opened) { + if (!yaml_emitter_open(emitter)) goto error; + } + + if (STACK_EMPTY(emitter, document->nodes)) { + if (!yaml_emitter_close(emitter)) goto error; + yaml_emitter_delete_document_and_anchors(emitter); + return 1; + } + + assert(emitter->opened); /* Emitter should be opened. */ + + emitter->anchors = yaml_malloc(sizeof(*(emitter->anchors)) + * (document->nodes.top - document->nodes.start)); + if (!emitter->anchors) goto error; + memset(emitter->anchors, 0, sizeof(*(emitter->anchors)) + * (document->nodes.top - document->nodes.start)); + + DOCUMENT_START_EVENT_INIT(event, document->version_directive, + document->tag_directives.start, document->tag_directives.end, + document->start_implicit, mark, mark); + if (!yaml_emitter_emit(emitter, &event)) goto error; + + yaml_emitter_anchor_node(emitter, 1); + if (!yaml_emitter_dump_node(emitter, 1)) goto error; + + DOCUMENT_END_EVENT_INIT(event, document->end_implicit, mark, mark); + if (!yaml_emitter_emit(emitter, &event)) goto error; + + yaml_emitter_delete_document_and_anchors(emitter); + + return 1; + +error: + + yaml_emitter_delete_document_and_anchors(emitter); + + return 0; +} + +/* + * Clean up the emitter object after a document is dumped. + */ + +static void +yaml_emitter_delete_document_and_anchors(yaml_emitter_t *emitter) +{ + int index; + + if (!emitter->anchors) { + yaml_document_delete(emitter->document); + emitter->document = NULL; + return; + } + + for (index = 0; emitter->document->nodes.start + index + < emitter->document->nodes.top; index ++) { + yaml_node_t node = emitter->document->nodes.start[index]; + if (!emitter->anchors[index].serialized) { + yaml_free(node.tag); + if (node.type == YAML_SCALAR_NODE) { + yaml_free(node.data.scalar.value); + } + } + if (node.type == YAML_SEQUENCE_NODE) { + STACK_DEL(emitter, node.data.sequence.items); + } + if (node.type == YAML_MAPPING_NODE) { + STACK_DEL(emitter, node.data.mapping.pairs); + } + } + + STACK_DEL(emitter, emitter->document->nodes); + yaml_free(emitter->anchors); + + emitter->anchors = NULL; + emitter->last_anchor_id = 0; + emitter->document = NULL; +} + +/* + * Check the references of a node and assign the anchor id if needed. + */ + +static void +yaml_emitter_anchor_node(yaml_emitter_t *emitter, int index) +{ + yaml_node_t *node = emitter->document->nodes.start + index - 1; + yaml_node_item_t *item; + yaml_node_pair_t *pair; + + emitter->anchors[index-1].references ++; + + if (emitter->anchors[index-1].references == 1) { + switch (node->type) { + case YAML_SEQUENCE_NODE: + for (item = node->data.sequence.items.start; + item < node->data.sequence.items.top; item ++) { + yaml_emitter_anchor_node(emitter, *item); + } + break; + case YAML_MAPPING_NODE: + for (pair = node->data.mapping.pairs.start; + pair < node->data.mapping.pairs.top; pair ++) { + yaml_emitter_anchor_node(emitter, pair->key); + yaml_emitter_anchor_node(emitter, pair->value); + } + break; + default: + break; + } + } + + else if (emitter->anchors[index-1].references == 2) { + emitter->anchors[index-1].anchor = (++ emitter->last_anchor_id); + } +} + +/* + * Generate a textual representation for an anchor. + */ + +#define ANCHOR_TEMPLATE "id%03d" +#define ANCHOR_TEMPLATE_LENGTH 16 + +static yaml_char_t * +yaml_emitter_generate_anchor(yaml_emitter_t *emitter, int anchor_id) +{ + yaml_char_t *anchor = yaml_malloc(ANCHOR_TEMPLATE_LENGTH); + + if (!anchor) return NULL; + + sprintf((char *)anchor, ANCHOR_TEMPLATE, anchor_id); + + return anchor; +} + +/* + * Serialize a node. + */ + +static int +yaml_emitter_dump_node(yaml_emitter_t *emitter, int index) +{ + yaml_node_t *node = emitter->document->nodes.start + index - 1; + int anchor_id = emitter->anchors[index-1].anchor; + yaml_char_t *anchor = NULL; + + if (anchor_id) { + anchor = yaml_emitter_generate_anchor(emitter, anchor_id); + if (!anchor) return 0; + } + + if (emitter->anchors[index-1].serialized) { + return yaml_emitter_dump_alias(emitter, anchor); + } + + emitter->anchors[index-1].serialized = 1; + + switch (node->type) { + case YAML_SCALAR_NODE: + return yaml_emitter_dump_scalar(emitter, node, anchor); + case YAML_SEQUENCE_NODE: + return yaml_emitter_dump_sequence(emitter, node, anchor); + case YAML_MAPPING_NODE: + return yaml_emitter_dump_mapping(emitter, node, anchor); + default: + assert(0); /* Could not happen. */ + break; + } + + return 0; /* Could not happen. */ +} + +/* + * Serialize an alias. + */ + +static int +yaml_emitter_dump_alias(yaml_emitter_t *emitter, yaml_char_t *anchor) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + ALIAS_EVENT_INIT(event, anchor, mark, mark); + + return yaml_emitter_emit(emitter, &event); +} + +/* + * Serialize a scalar. + */ + +static int +yaml_emitter_dump_scalar(yaml_emitter_t *emitter, yaml_node_t *node, + yaml_char_t *anchor) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + int plain_implicit = (strcmp((char *)node->tag, + YAML_DEFAULT_SCALAR_TAG) == 0); + int quoted_implicit = (strcmp((char *)node->tag, + YAML_DEFAULT_SCALAR_TAG) == 0); + + SCALAR_EVENT_INIT(event, anchor, node->tag, node->data.scalar.value, + node->data.scalar.length, plain_implicit, quoted_implicit, + node->data.scalar.style, mark, mark); + + return yaml_emitter_emit(emitter, &event); +} + +/* + * Serialize a sequence. + */ + +static int +yaml_emitter_dump_sequence(yaml_emitter_t *emitter, yaml_node_t *node, + yaml_char_t *anchor) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_SEQUENCE_TAG) == 0); + + yaml_node_item_t *item; + + SEQUENCE_START_EVENT_INIT(event, anchor, node->tag, implicit, + node->data.sequence.style, mark, mark); + if (!yaml_emitter_emit(emitter, &event)) return 0; + + for (item = node->data.sequence.items.start; + item < node->data.sequence.items.top; item ++) { + if (!yaml_emitter_dump_node(emitter, *item)) return 0; + } + + SEQUENCE_END_EVENT_INIT(event, mark, mark); + if (!yaml_emitter_emit(emitter, &event)) return 0; + + return 1; +} + +/* + * Serialize a mapping. + */ + +static int +yaml_emitter_dump_mapping(yaml_emitter_t *emitter, yaml_node_t *node, + yaml_char_t *anchor) +{ + yaml_event_t event; + yaml_mark_t mark = { 0, 0, 0 }; + + int implicit = (strcmp((char *)node->tag, YAML_DEFAULT_MAPPING_TAG) == 0); + + yaml_node_pair_t *pair; + + MAPPING_START_EVENT_INIT(event, anchor, node->tag, implicit, + node->data.mapping.style, mark, mark); + if (!yaml_emitter_emit(emitter, &event)) return 0; + + for (pair = node->data.mapping.pairs.start; + pair < node->data.mapping.pairs.top; pair ++) { + if (!yaml_emitter_dump_node(emitter, pair->key)) return 0; + if (!yaml_emitter_dump_node(emitter, pair->value)) return 0; + } + + MAPPING_END_EVENT_INIT(event, mark, mark); + if (!yaml_emitter_emit(emitter, &event)) return 0; + + return 1; +} + diff --git a/src/external/yaml/emitter.c b/src/external/yaml/emitter.c new file mode 100644 index 0000000..c4b56a2 --- /dev/null +++ b/src/external/yaml/emitter.c @@ -0,0 +1,2329 @@ + +#include "yaml_private.h" + +/* + * Flush the buffer if needed. + */ + +#define FLUSH(emitter) \ + ((emitter->buffer.pointer+5 < emitter->buffer.end) \ + || yaml_emitter_flush(emitter)) + +/* + * Put a character to the output buffer. + */ + +#define PUT(emitter,value) \ + (FLUSH(emitter) \ + && (*(emitter->buffer.pointer++) = (yaml_char_t)(value), \ + emitter->column ++, \ + 1)) + +/* + * Put a line break to the output buffer. + */ + +#define PUT_BREAK(emitter) \ + (FLUSH(emitter) \ + && ((emitter->line_break == YAML_CR_BREAK ? \ + (*(emitter->buffer.pointer++) = (yaml_char_t) '\r') : \ + emitter->line_break == YAML_LN_BREAK ? \ + (*(emitter->buffer.pointer++) = (yaml_char_t) '\n') : \ + emitter->line_break == YAML_CRLN_BREAK ? \ + (*(emitter->buffer.pointer++) = (yaml_char_t) '\r', \ + *(emitter->buffer.pointer++) = (yaml_char_t) '\n') : 0), \ + emitter->column = 0, \ + emitter->line ++, \ + 1)) + +/* + * Copy a character from a string into buffer. + */ + +#define WRITE(emitter,string) \ + (FLUSH(emitter) \ + && (COPY(emitter->buffer,string), \ + emitter->column ++, \ + 1)) + +/* + * Copy a line break character from a string into buffer. + */ + +#define WRITE_BREAK(emitter,string) \ + (FLUSH(emitter) \ + && (CHECK(string,'\n') ? \ + (PUT_BREAK(emitter), \ + string.pointer ++, \ + 1) : \ + (COPY(emitter->buffer,string), \ + emitter->column = 0, \ + emitter->line ++, \ + 1))) + +/* + * API functions. + */ + +YAML_DECLARE(int) +yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event); + +/* + * Utility functions. + */ + +static int +yaml_emitter_set_emitter_error(yaml_emitter_t *emitter, const char *problem); + +static int +yaml_emitter_need_more_events(yaml_emitter_t *emitter); + +static int +yaml_emitter_append_tag_directive(yaml_emitter_t *emitter, + yaml_tag_directive_t value, int allow_duplicates); + +static int +yaml_emitter_increase_indent(yaml_emitter_t *emitter, + int flow, int indentless); + +/* + * State functions. + */ + +static int +yaml_emitter_state_machine(yaml_emitter_t *emitter, yaml_event_t *event); + +static int +yaml_emitter_emit_stream_start(yaml_emitter_t *emitter, + yaml_event_t *event); + +static int +yaml_emitter_emit_document_start(yaml_emitter_t *emitter, + yaml_event_t *event, int first); + +static int +yaml_emitter_emit_document_content(yaml_emitter_t *emitter, + yaml_event_t *event); + +static int +yaml_emitter_emit_document_end(yaml_emitter_t *emitter, + yaml_event_t *event); + +static int +yaml_emitter_emit_flow_sequence_item(yaml_emitter_t *emitter, + yaml_event_t *event, int first); + +static int +yaml_emitter_emit_flow_mapping_key(yaml_emitter_t *emitter, + yaml_event_t *event, int first); + +static int +yaml_emitter_emit_flow_mapping_value(yaml_emitter_t *emitter, + yaml_event_t *event, int simple); + +static int +yaml_emitter_emit_block_sequence_item(yaml_emitter_t *emitter, + yaml_event_t *event, int first); + +static int +yaml_emitter_emit_block_mapping_key(yaml_emitter_t *emitter, + yaml_event_t *event, int first); + +static int +yaml_emitter_emit_block_mapping_value(yaml_emitter_t *emitter, + yaml_event_t *event, int simple); + +static int +yaml_emitter_emit_node(yaml_emitter_t *emitter, yaml_event_t *event, + int root, int sequence, int mapping, int simple_key); + +static int +yaml_emitter_emit_alias(yaml_emitter_t *emitter, yaml_event_t *event); + +static int +yaml_emitter_emit_scalar(yaml_emitter_t *emitter, yaml_event_t *event); + +static int +yaml_emitter_emit_sequence_start(yaml_emitter_t *emitter, yaml_event_t *event); + +static int +yaml_emitter_emit_mapping_start(yaml_emitter_t *emitter, yaml_event_t *event); + +/* + * Checkers. + */ + +static int +yaml_emitter_check_empty_document(yaml_emitter_t *emitter); + +static int +yaml_emitter_check_empty_sequence(yaml_emitter_t *emitter); + +static int +yaml_emitter_check_empty_mapping(yaml_emitter_t *emitter); + +static int +yaml_emitter_check_simple_key(yaml_emitter_t *emitter); + +static int +yaml_emitter_select_scalar_style(yaml_emitter_t *emitter, yaml_event_t *event); + +/* + * Processors. + */ + +static int +yaml_emitter_process_anchor(yaml_emitter_t *emitter); + +static int +yaml_emitter_process_tag(yaml_emitter_t *emitter); + +static int +yaml_emitter_process_scalar(yaml_emitter_t *emitter); + +/* + * Analyzers. + */ + +static int +yaml_emitter_analyze_version_directive(yaml_emitter_t *emitter, + yaml_version_directive_t version_directive); + +static int +yaml_emitter_analyze_tag_directive(yaml_emitter_t *emitter, + yaml_tag_directive_t tag_directive); + +static int +yaml_emitter_analyze_anchor(yaml_emitter_t *emitter, + yaml_char_t *anchor, int alias); + +static int +yaml_emitter_analyze_tag(yaml_emitter_t *emitter, + yaml_char_t *tag); + +static int +yaml_emitter_analyze_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length); + +static int +yaml_emitter_analyze_event(yaml_emitter_t *emitter, + yaml_event_t *event); + +/* + * Writers. + */ + +static int +yaml_emitter_write_bom(yaml_emitter_t *emitter); + +static int +yaml_emitter_write_indent(yaml_emitter_t *emitter); + +static int +yaml_emitter_write_indicator(yaml_emitter_t *emitter, + char *indicator, int need_whitespace, + int is_whitespace, int is_indention); + +static int +yaml_emitter_write_anchor(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length); + +static int +yaml_emitter_write_tag_handle(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length); + +static int +yaml_emitter_write_tag_content(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int need_whitespace); + +static int +yaml_emitter_write_plain_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int allow_breaks); + +static int +yaml_emitter_write_single_quoted_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int allow_breaks); + +static int +yaml_emitter_write_double_quoted_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int allow_breaks); + +static int +yaml_emitter_write_block_scalar_hints(yaml_emitter_t *emitter, + yaml_string_t string); + +static int +yaml_emitter_write_literal_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length); + +static int +yaml_emitter_write_folded_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length); + +/* + * Set an emitter error and return 0. + */ + +static int +yaml_emitter_set_emitter_error(yaml_emitter_t *emitter, const char *problem) +{ + emitter->error = YAML_EMITTER_ERROR; + emitter->problem = problem; + + return 0; +} + +/* + * Emit an event. + */ + +YAML_DECLARE(int) +yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event) +{ + if (!ENQUEUE(emitter, emitter->events, *event)) { + yaml_event_delete(event); + return 0; + } + + while (!yaml_emitter_need_more_events(emitter)) { + if (!yaml_emitter_analyze_event(emitter, emitter->events.head)) + return 0; + if (!yaml_emitter_state_machine(emitter, emitter->events.head)) + return 0; + yaml_event_delete(&DEQUEUE(emitter, emitter->events)); + } + + return 1; +} + +/* + * Check if we need to accumulate more events before emitting. + * + * We accumulate extra + * - 1 event for DOCUMENT-START + * - 2 events for SEQUENCE-START + * - 3 events for MAPPING-START + */ + +static int +yaml_emitter_need_more_events(yaml_emitter_t *emitter) +{ + int level = 0; + int accumulate = 0; + yaml_event_t *event; + + if (QUEUE_EMPTY(emitter, emitter->events)) + return 1; + + switch (emitter->events.head->type) { + case YAML_DOCUMENT_START_EVENT: + accumulate = 1; + break; + case YAML_SEQUENCE_START_EVENT: + accumulate = 2; + break; + case YAML_MAPPING_START_EVENT: + accumulate = 3; + break; + default: + return 0; + } + + if (emitter->events.tail - emitter->events.head > accumulate) + return 0; + + for (event = emitter->events.head; event != emitter->events.tail; event ++) { + switch (event->type) { + case YAML_STREAM_START_EVENT: + case YAML_DOCUMENT_START_EVENT: + case YAML_SEQUENCE_START_EVENT: + case YAML_MAPPING_START_EVENT: + level += 1; + break; + case YAML_STREAM_END_EVENT: + case YAML_DOCUMENT_END_EVENT: + case YAML_SEQUENCE_END_EVENT: + case YAML_MAPPING_END_EVENT: + level -= 1; + break; + default: + break; + } + if (!level) + return 0; + } + + return 1; +} + +/* + * Append a directive to the directives stack. + */ + +static int +yaml_emitter_append_tag_directive(yaml_emitter_t *emitter, + yaml_tag_directive_t value, int allow_duplicates) +{ + yaml_tag_directive_t *tag_directive; + yaml_tag_directive_t copy = { NULL, NULL }; + + for (tag_directive = emitter->tag_directives.start; + tag_directive != emitter->tag_directives.top; tag_directive ++) { + if (strcmp((char *)value.handle, (char *)tag_directive->handle) == 0) { + if (allow_duplicates) + return 1; + return yaml_emitter_set_emitter_error(emitter, + "duplicate %TAG directive"); + } + } + + copy.handle = yaml_strdup(value.handle); + copy.prefix = yaml_strdup(value.prefix); + if (!copy.handle || !copy.prefix) { + emitter->error = YAML_MEMORY_ERROR; + goto error; + } + + if (!PUSH(emitter, emitter->tag_directives, copy)) + goto error; + + return 1; + +error: + yaml_free(copy.handle); + yaml_free(copy.prefix); + return 0; +} + +/* + * Increase the indentation level. + */ + +static int +yaml_emitter_increase_indent(yaml_emitter_t *emitter, + int flow, int indentless) +{ + if (!PUSH(emitter, emitter->indents, emitter->indent)) + return 0; + + if (emitter->indent < 0) { + emitter->indent = flow ? emitter->best_indent : 0; + } + else if (!indentless) { + emitter->indent += emitter->best_indent; + } + + return 1; +} + +/* + * State dispatcher. + */ + +static int +yaml_emitter_state_machine(yaml_emitter_t *emitter, yaml_event_t *event) +{ + switch (emitter->state) + { + case YAML_EMIT_STREAM_START_STATE: + return yaml_emitter_emit_stream_start(emitter, event); + + case YAML_EMIT_FIRST_DOCUMENT_START_STATE: + return yaml_emitter_emit_document_start(emitter, event, 1); + + case YAML_EMIT_DOCUMENT_START_STATE: + return yaml_emitter_emit_document_start(emitter, event, 0); + + case YAML_EMIT_DOCUMENT_CONTENT_STATE: + return yaml_emitter_emit_document_content(emitter, event); + + case YAML_EMIT_DOCUMENT_END_STATE: + return yaml_emitter_emit_document_end(emitter, event); + + case YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE: + return yaml_emitter_emit_flow_sequence_item(emitter, event, 1); + + case YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE: + return yaml_emitter_emit_flow_sequence_item(emitter, event, 0); + + case YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE: + return yaml_emitter_emit_flow_mapping_key(emitter, event, 1); + + case YAML_EMIT_FLOW_MAPPING_KEY_STATE: + return yaml_emitter_emit_flow_mapping_key(emitter, event, 0); + + case YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE: + return yaml_emitter_emit_flow_mapping_value(emitter, event, 1); + + case YAML_EMIT_FLOW_MAPPING_VALUE_STATE: + return yaml_emitter_emit_flow_mapping_value(emitter, event, 0); + + case YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE: + return yaml_emitter_emit_block_sequence_item(emitter, event, 1); + + case YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE: + return yaml_emitter_emit_block_sequence_item(emitter, event, 0); + + case YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE: + return yaml_emitter_emit_block_mapping_key(emitter, event, 1); + + case YAML_EMIT_BLOCK_MAPPING_KEY_STATE: + return yaml_emitter_emit_block_mapping_key(emitter, event, 0); + + case YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE: + return yaml_emitter_emit_block_mapping_value(emitter, event, 1); + + case YAML_EMIT_BLOCK_MAPPING_VALUE_STATE: + return yaml_emitter_emit_block_mapping_value(emitter, event, 0); + + case YAML_EMIT_END_STATE: + return yaml_emitter_set_emitter_error(emitter, + "expected nothing after STREAM-END"); + + default: + assert(1); /* Invalid state. */ + } + + return 0; +} + +/* + * Expect STREAM-START. + */ + +static int +yaml_emitter_emit_stream_start(yaml_emitter_t *emitter, + yaml_event_t *event) +{ + if (event->type == YAML_STREAM_START_EVENT) + { + if (!emitter->encoding) { + emitter->encoding = event->data.stream_start.encoding; + } + + if (!emitter->encoding) { + emitter->encoding = YAML_UTF8_ENCODING; + } + + if (emitter->best_indent < 2 || emitter->best_indent > 9) { + emitter->best_indent = 2; + } + + if (emitter->best_width >= 0 + && emitter->best_width <= emitter->best_indent*2) { + emitter->best_width = 80; + } + + if (emitter->best_width < 0) { + emitter->best_width = INT_MAX; + } + + if (!emitter->line_break) { + emitter->line_break = YAML_LN_BREAK; + } + + emitter->indent = -1; + + emitter->line = 0; + emitter->column = 0; + emitter->whitespace = 1; + emitter->indention = 1; + + if (emitter->encoding != YAML_UTF8_ENCODING) { + if (!yaml_emitter_write_bom(emitter)) + return 0; + } + + emitter->state = YAML_EMIT_FIRST_DOCUMENT_START_STATE; + + return 1; + } + + return yaml_emitter_set_emitter_error(emitter, + "expected STREAM-START"); +} + +/* + * Expect DOCUMENT-START or STREAM-END. + */ + +static int +yaml_emitter_emit_document_start(yaml_emitter_t *emitter, + yaml_event_t *event, int first) +{ + if (event->type == YAML_DOCUMENT_START_EVENT) + { + yaml_tag_directive_t default_tag_directives[] = { + {(yaml_char_t *)"!", (yaml_char_t *)"!"}, + {(yaml_char_t *)"!!", (yaml_char_t *)"tag:yaml.org,2002:"}, + {NULL, NULL} + }; + yaml_tag_directive_t *tag_directive; + int implicit; + + if (event->data.document_start.version_directive) { + if (!yaml_emitter_analyze_version_directive(emitter, + *event->data.document_start.version_directive)) + return 0; + } + + for (tag_directive = event->data.document_start.tag_directives.start; + tag_directive != event->data.document_start.tag_directives.end; + tag_directive ++) { + if (!yaml_emitter_analyze_tag_directive(emitter, *tag_directive)) + return 0; + if (!yaml_emitter_append_tag_directive(emitter, *tag_directive, 0)) + return 0; + } + + for (tag_directive = default_tag_directives; + tag_directive->handle; tag_directive ++) { + if (!yaml_emitter_append_tag_directive(emitter, *tag_directive, 1)) + return 0; + } + + implicit = event->data.document_start.implicit; + if (!first || emitter->canonical) { + implicit = 0; + } + + if ((event->data.document_start.version_directive || + (event->data.document_start.tag_directives.start + != event->data.document_start.tag_directives.end)) && + emitter->open_ended) + { + if (!yaml_emitter_write_indicator(emitter, "...", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + + if (event->data.document_start.version_directive) { + implicit = 0; + if (!yaml_emitter_write_indicator(emitter, "%YAML", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_indicator(emitter, "1.1", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + + if (event->data.document_start.tag_directives.start + != event->data.document_start.tag_directives.end) { + implicit = 0; + for (tag_directive = event->data.document_start.tag_directives.start; + tag_directive != event->data.document_start.tag_directives.end; + tag_directive ++) { + if (!yaml_emitter_write_indicator(emitter, "%TAG", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_tag_handle(emitter, tag_directive->handle, + strlen((char *)tag_directive->handle))) + return 0; + if (!yaml_emitter_write_tag_content(emitter, tag_directive->prefix, + strlen((char *)tag_directive->prefix), 1)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + } + + if (yaml_emitter_check_empty_document(emitter)) { + implicit = 0; + } + + if (!implicit) { + if (!yaml_emitter_write_indent(emitter)) + return 0; + if (!yaml_emitter_write_indicator(emitter, "---", 1, 0, 0)) + return 0; + if (emitter->canonical) { + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + } + + emitter->state = YAML_EMIT_DOCUMENT_CONTENT_STATE; + + return 1; + } + + else if (event->type == YAML_STREAM_END_EVENT) + { + if (emitter->open_ended) + { + if (!yaml_emitter_write_indicator(emitter, "...", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + + if (!yaml_emitter_flush(emitter)) + return 0; + + emitter->state = YAML_EMIT_END_STATE; + + return 1; + } + + return yaml_emitter_set_emitter_error(emitter, + "expected DOCUMENT-START or STREAM-END"); +} + +/* + * Expect the root node. + */ + +static int +yaml_emitter_emit_document_content(yaml_emitter_t *emitter, + yaml_event_t *event) +{ + if (!PUSH(emitter, emitter->states, YAML_EMIT_DOCUMENT_END_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 1, 0, 0, 0); +} + +/* + * Expect DOCUMENT-END. + */ + +static int +yaml_emitter_emit_document_end(yaml_emitter_t *emitter, + yaml_event_t *event) +{ + if (event->type == YAML_DOCUMENT_END_EVENT) + { + if (!yaml_emitter_write_indent(emitter)) + return 0; + if (!event->data.document_end.implicit) { + if (!yaml_emitter_write_indicator(emitter, "...", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + if (!yaml_emitter_flush(emitter)) + return 0; + + emitter->state = YAML_EMIT_DOCUMENT_START_STATE; + + while (!STACK_EMPTY(emitter, emitter->tag_directives)) { + yaml_tag_directive_t tag_directive = POP(emitter, + emitter->tag_directives); + yaml_free(tag_directive.handle); + yaml_free(tag_directive.prefix); + } + + return 1; + } + + return yaml_emitter_set_emitter_error(emitter, + "expected DOCUMENT-END"); +} + +/* + * + * Expect a flow item node. + */ + +static int +yaml_emitter_emit_flow_sequence_item(yaml_emitter_t *emitter, + yaml_event_t *event, int first) +{ + if (first) + { + if (!yaml_emitter_write_indicator(emitter, "[", 1, 1, 0)) + return 0; + if (!yaml_emitter_increase_indent(emitter, 1, 0)) + return 0; + emitter->flow_level ++; + } + + if (event->type == YAML_SEQUENCE_END_EVENT) + { + emitter->flow_level --; + emitter->indent = POP(emitter, emitter->indents); + if (emitter->canonical && !first) { + if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + if (!yaml_emitter_write_indicator(emitter, "]", 0, 0, 0)) + return 0; + emitter->state = POP(emitter, emitter->states); + + return 1; + } + + if (!first) { + if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0)) + return 0; + } + + if (emitter->canonical || emitter->column > emitter->best_width) { + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + if (!PUSH(emitter, emitter->states, YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 1, 0, 0); +} + +/* + * Expect a flow key node. + */ + +static int +yaml_emitter_emit_flow_mapping_key(yaml_emitter_t *emitter, + yaml_event_t *event, int first) +{ + if (first) + { + if (!yaml_emitter_write_indicator(emitter, "{", 1, 1, 0)) + return 0; + if (!yaml_emitter_increase_indent(emitter, 1, 0)) + return 0; + emitter->flow_level ++; + } + + if (event->type == YAML_MAPPING_END_EVENT) + { + emitter->flow_level --; + emitter->indent = POP(emitter, emitter->indents); + if (emitter->canonical && !first) { + if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0)) + return 0; + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + if (!yaml_emitter_write_indicator(emitter, "}", 0, 0, 0)) + return 0; + emitter->state = POP(emitter, emitter->states); + + return 1; + } + + if (!first) { + if (!yaml_emitter_write_indicator(emitter, ",", 0, 0, 0)) + return 0; + } + if (emitter->canonical || emitter->column > emitter->best_width) { + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + + if (!emitter->canonical && yaml_emitter_check_simple_key(emitter)) + { + if (!PUSH(emitter, emitter->states, + YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 1); + } + else + { + if (!yaml_emitter_write_indicator(emitter, "?", 1, 0, 0)) + return 0; + if (!PUSH(emitter, emitter->states, + YAML_EMIT_FLOW_MAPPING_VALUE_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0); + } +} + +/* + * Expect a flow value node. + */ + +static int +yaml_emitter_emit_flow_mapping_value(yaml_emitter_t *emitter, + yaml_event_t *event, int simple) +{ + if (simple) { + if (!yaml_emitter_write_indicator(emitter, ":", 0, 0, 0)) + return 0; + } + else { + if (emitter->canonical || emitter->column > emitter->best_width) { + if (!yaml_emitter_write_indent(emitter)) + return 0; + } + if (!yaml_emitter_write_indicator(emitter, ":", 1, 0, 0)) + return 0; + } + if (!PUSH(emitter, emitter->states, YAML_EMIT_FLOW_MAPPING_KEY_STATE)) + return 0; + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0); +} + +/* + * Expect a block item node. + */ + +static int +yaml_emitter_emit_block_sequence_item(yaml_emitter_t *emitter, + yaml_event_t *event, int first) +{ + if (first) + { + if (!yaml_emitter_increase_indent(emitter, 0, + (emitter->mapping_context && !emitter->indention))) + return 0; + } + + if (event->type == YAML_SEQUENCE_END_EVENT) + { + emitter->indent = POP(emitter, emitter->indents); + emitter->state = POP(emitter, emitter->states); + + return 1; + } + + if (!yaml_emitter_write_indent(emitter)) + return 0; + if (!yaml_emitter_write_indicator(emitter, "-", 1, 0, 1)) + return 0; + if (!PUSH(emitter, emitter->states, + YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 1, 0, 0); +} + +/* + * Expect a block key node. + */ + +static int +yaml_emitter_emit_block_mapping_key(yaml_emitter_t *emitter, + yaml_event_t *event, int first) +{ + if (first) + { + if (!yaml_emitter_increase_indent(emitter, 0, 0)) + return 0; + } + + if (event->type == YAML_MAPPING_END_EVENT) + { + emitter->indent = POP(emitter, emitter->indents); + emitter->state = POP(emitter, emitter->states); + + return 1; + } + + if (!yaml_emitter_write_indent(emitter)) + return 0; + + if (yaml_emitter_check_simple_key(emitter)) + { + if (!PUSH(emitter, emitter->states, + YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 1); + } + else + { + if (!yaml_emitter_write_indicator(emitter, "?", 1, 0, 1)) + return 0; + if (!PUSH(emitter, emitter->states, + YAML_EMIT_BLOCK_MAPPING_VALUE_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0); + } +} + +/* + * Expect a block value node. + */ + +static int +yaml_emitter_emit_block_mapping_value(yaml_emitter_t *emitter, + yaml_event_t *event, int simple) +{ + if (simple) { + if (!yaml_emitter_write_indicator(emitter, ":", 0, 0, 0)) + return 0; + } + else { + if (!yaml_emitter_write_indent(emitter)) + return 0; + if (!yaml_emitter_write_indicator(emitter, ":", 1, 0, 1)) + return 0; + } + if (!PUSH(emitter, emitter->states, + YAML_EMIT_BLOCK_MAPPING_KEY_STATE)) + return 0; + + return yaml_emitter_emit_node(emitter, event, 0, 0, 1, 0); +} + +/* + * Expect a node. + */ + +static int +yaml_emitter_emit_node(yaml_emitter_t *emitter, yaml_event_t *event, + int root, int sequence, int mapping, int simple_key) +{ + emitter->root_context = root; + emitter->sequence_context = sequence; + emitter->mapping_context = mapping; + emitter->simple_key_context = simple_key; + + switch (event->type) + { + case YAML_ALIAS_EVENT: + return yaml_emitter_emit_alias(emitter, event); + + case YAML_SCALAR_EVENT: + return yaml_emitter_emit_scalar(emitter, event); + + case YAML_SEQUENCE_START_EVENT: + return yaml_emitter_emit_sequence_start(emitter, event); + + case YAML_MAPPING_START_EVENT: + return yaml_emitter_emit_mapping_start(emitter, event); + + default: + return yaml_emitter_set_emitter_error(emitter, + "expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS"); + } + + return 0; +} + +/* + * Expect ALIAS. + */ + +static int +yaml_emitter_emit_alias(yaml_emitter_t *emitter, yaml_event_t *event) +{ + if (!yaml_emitter_process_anchor(emitter)) + return 0; + emitter->state = POP(emitter, emitter->states); + + return 1; +} + +/* + * Expect SCALAR. + */ + +static int +yaml_emitter_emit_scalar(yaml_emitter_t *emitter, yaml_event_t *event) +{ + if (!yaml_emitter_select_scalar_style(emitter, event)) + return 0; + if (!yaml_emitter_process_anchor(emitter)) + return 0; + if (!yaml_emitter_process_tag(emitter)) + return 0; + if (!yaml_emitter_increase_indent(emitter, 1, 0)) + return 0; + if (!yaml_emitter_process_scalar(emitter)) + return 0; + emitter->indent = POP(emitter, emitter->indents); + emitter->state = POP(emitter, emitter->states); + + return 1; +} + +/* + * Expect SEQUENCE-START. + */ + +static int +yaml_emitter_emit_sequence_start(yaml_emitter_t *emitter, yaml_event_t *event) +{ + if (!yaml_emitter_process_anchor(emitter)) + return 0; + if (!yaml_emitter_process_tag(emitter)) + return 0; + + if (emitter->flow_level || emitter->canonical + || event->data.sequence_start.style == YAML_FLOW_SEQUENCE_STYLE + || yaml_emitter_check_empty_sequence(emitter)) { + emitter->state = YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE; + } + else { + emitter->state = YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE; + } + + return 1; +} + +/* + * Expect MAPPING-START. + */ + +static int +yaml_emitter_emit_mapping_start(yaml_emitter_t *emitter, yaml_event_t *event) +{ + if (!yaml_emitter_process_anchor(emitter)) + return 0; + if (!yaml_emitter_process_tag(emitter)) + return 0; + + if (emitter->flow_level || emitter->canonical + || event->data.mapping_start.style == YAML_FLOW_MAPPING_STYLE + || yaml_emitter_check_empty_mapping(emitter)) { + emitter->state = YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE; + } + else { + emitter->state = YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE; + } + + return 1; +} + +/* + * Check if the document content is an empty scalar. + */ + +static int +yaml_emitter_check_empty_document(yaml_emitter_t *emitter) +{ + return 0; +} + +/* + * Check if the next events represent an empty sequence. + */ + +static int +yaml_emitter_check_empty_sequence(yaml_emitter_t *emitter) +{ + if (emitter->events.tail - emitter->events.head < 2) + return 0; + + return (emitter->events.head[0].type == YAML_SEQUENCE_START_EVENT + && emitter->events.head[1].type == YAML_SEQUENCE_END_EVENT); +} + +/* + * Check if the next events represent an empty mapping. + */ + +static int +yaml_emitter_check_empty_mapping(yaml_emitter_t *emitter) +{ + if (emitter->events.tail - emitter->events.head < 2) + return 0; + + return (emitter->events.head[0].type == YAML_MAPPING_START_EVENT + && emitter->events.head[1].type == YAML_MAPPING_END_EVENT); +} + +/* + * Check if the next node can be expressed as a simple key. + */ + +static int +yaml_emitter_check_simple_key(yaml_emitter_t *emitter) +{ + yaml_event_t *event = emitter->events.head; + size_t length = 0; + + switch (event->type) + { + case YAML_ALIAS_EVENT: + length += emitter->anchor_data.anchor_length; + break; + + case YAML_SCALAR_EVENT: + if (emitter->scalar_data.multiline) + return 0; + length += emitter->anchor_data.anchor_length + + emitter->tag_data.handle_length + + emitter->tag_data.suffix_length + + emitter->scalar_data.length; + break; + + case YAML_SEQUENCE_START_EVENT: + if (!yaml_emitter_check_empty_sequence(emitter)) + return 0; + length += emitter->anchor_data.anchor_length + + emitter->tag_data.handle_length + + emitter->tag_data.suffix_length; + break; + + case YAML_MAPPING_START_EVENT: + if (!yaml_emitter_check_empty_mapping(emitter)) + return 0; + length += emitter->anchor_data.anchor_length + + emitter->tag_data.handle_length + + emitter->tag_data.suffix_length; + break; + + default: + return 0; + } + + if (length > 128) + return 0; + + return 1; +} + +/* + * Determine an acceptable scalar style. + */ + +static int +yaml_emitter_select_scalar_style(yaml_emitter_t *emitter, yaml_event_t *event) +{ + yaml_scalar_style_t style = event->data.scalar.style; + int no_tag = (!emitter->tag_data.handle && !emitter->tag_data.suffix); + + if (no_tag && !event->data.scalar.plain_implicit + && !event->data.scalar.quoted_implicit) { + return yaml_emitter_set_emitter_error(emitter, + "neither tag nor implicit flags are specified"); + } + + if (style == YAML_ANY_SCALAR_STYLE) + style = YAML_PLAIN_SCALAR_STYLE; + + if (emitter->canonical) + style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; + + if (emitter->simple_key_context && emitter->scalar_data.multiline) + style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; + + if (style == YAML_PLAIN_SCALAR_STYLE) + { + if ((emitter->flow_level && !emitter->scalar_data.flow_plain_allowed) + || (!emitter->flow_level && !emitter->scalar_data.block_plain_allowed)) + style = YAML_SINGLE_QUOTED_SCALAR_STYLE; + if (!emitter->scalar_data.length + && (emitter->flow_level || emitter->simple_key_context)) + style = YAML_SINGLE_QUOTED_SCALAR_STYLE; + if (no_tag && !event->data.scalar.plain_implicit) + style = YAML_SINGLE_QUOTED_SCALAR_STYLE; + } + + if (style == YAML_SINGLE_QUOTED_SCALAR_STYLE) + { + if (!emitter->scalar_data.single_quoted_allowed) + style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; + } + + if (style == YAML_LITERAL_SCALAR_STYLE || style == YAML_FOLDED_SCALAR_STYLE) + { + if (!emitter->scalar_data.block_allowed + || emitter->flow_level || emitter->simple_key_context) + style = YAML_DOUBLE_QUOTED_SCALAR_STYLE; + } + + if (no_tag && !event->data.scalar.quoted_implicit + && style != YAML_PLAIN_SCALAR_STYLE) + { + emitter->tag_data.handle = (yaml_char_t *)"!"; + emitter->tag_data.handle_length = 1; + } + + emitter->scalar_data.style = style; + + return 1; +} + +/* + * Write an achor. + */ + +static int +yaml_emitter_process_anchor(yaml_emitter_t *emitter) +{ + if (!emitter->anchor_data.anchor) + return 1; + + if (!yaml_emitter_write_indicator(emitter, + (emitter->anchor_data.alias ? "*" : "&"), 1, 0, 0)) + return 0; + + return yaml_emitter_write_anchor(emitter, + emitter->anchor_data.anchor, emitter->anchor_data.anchor_length); +} + +/* + * Write a tag. + */ + +static int +yaml_emitter_process_tag(yaml_emitter_t *emitter) +{ + if (!emitter->tag_data.handle && !emitter->tag_data.suffix) + return 1; + + if (emitter->tag_data.handle) + { + if (!yaml_emitter_write_tag_handle(emitter, emitter->tag_data.handle, + emitter->tag_data.handle_length)) + return 0; + if (emitter->tag_data.suffix) { + if (!yaml_emitter_write_tag_content(emitter, emitter->tag_data.suffix, + emitter->tag_data.suffix_length, 0)) + return 0; + } + } + else + { + if (!yaml_emitter_write_indicator(emitter, "!<", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_tag_content(emitter, emitter->tag_data.suffix, + emitter->tag_data.suffix_length, 0)) + return 0; + if (!yaml_emitter_write_indicator(emitter, ">", 0, 0, 0)) + return 0; + } + + return 1; +} + +/* + * Write a scalar. + */ + +static int +yaml_emitter_process_scalar(yaml_emitter_t *emitter) +{ + switch (emitter->scalar_data.style) + { + case YAML_PLAIN_SCALAR_STYLE: + return yaml_emitter_write_plain_scalar(emitter, + emitter->scalar_data.value, emitter->scalar_data.length, + !emitter->simple_key_context); + + case YAML_SINGLE_QUOTED_SCALAR_STYLE: + return yaml_emitter_write_single_quoted_scalar(emitter, + emitter->scalar_data.value, emitter->scalar_data.length, + !emitter->simple_key_context); + + case YAML_DOUBLE_QUOTED_SCALAR_STYLE: + return yaml_emitter_write_double_quoted_scalar(emitter, + emitter->scalar_data.value, emitter->scalar_data.length, + !emitter->simple_key_context); + + case YAML_LITERAL_SCALAR_STYLE: + return yaml_emitter_write_literal_scalar(emitter, + emitter->scalar_data.value, emitter->scalar_data.length); + + case YAML_FOLDED_SCALAR_STYLE: + return yaml_emitter_write_folded_scalar(emitter, + emitter->scalar_data.value, emitter->scalar_data.length); + + default: + assert(1); /* Impossible. */ + } + + return 0; +} + +/* + * Check if a %YAML directive is valid. + */ + +static int +yaml_emitter_analyze_version_directive(yaml_emitter_t *emitter, + yaml_version_directive_t version_directive) +{ + if (version_directive.major != 1 || version_directive.minor != 1) { + return yaml_emitter_set_emitter_error(emitter, + "incompatible %YAML directive"); + } + + return 1; +} + +/* + * Check if a %TAG directive is valid. + */ + +static int +yaml_emitter_analyze_tag_directive(yaml_emitter_t *emitter, + yaml_tag_directive_t tag_directive) +{ + yaml_string_t handle; + yaml_string_t prefix; + size_t handle_length; + size_t prefix_length; + + handle_length = strlen((char *)tag_directive.handle); + prefix_length = strlen((char *)tag_directive.prefix); + STRING_ASSIGN(handle, tag_directive.handle, handle_length); + STRING_ASSIGN(prefix, tag_directive.prefix, prefix_length); + + if (handle.start == handle.end) { + return yaml_emitter_set_emitter_error(emitter, + "tag handle must not be empty"); + } + + if (handle.start[0] != '!') { + return yaml_emitter_set_emitter_error(emitter, + "tag handle must start with '!'"); + } + + if (handle.end[-1] != '!') { + return yaml_emitter_set_emitter_error(emitter, + "tag handle must end with '!'"); + } + + handle.pointer ++; + + while (handle.pointer < handle.end-1) { + if (!IS_ALPHA(handle)) { + return yaml_emitter_set_emitter_error(emitter, + "tag handle must contain alphanumerical characters only"); + } + MOVE(handle); + } + + if (prefix.start == prefix.end) { + return yaml_emitter_set_emitter_error(emitter, + "tag prefix must not be empty"); + } + + return 1; +} + +/* + * Check if an anchor is valid. + */ + +static int +yaml_emitter_analyze_anchor(yaml_emitter_t *emitter, + yaml_char_t *anchor, int alias) +{ + size_t anchor_length; + yaml_string_t string; + + anchor_length = strlen((char *)anchor); + STRING_ASSIGN(string, anchor, anchor_length); + + if (string.start == string.end) { + return yaml_emitter_set_emitter_error(emitter, alias ? + "alias value must not be empty" : + "anchor value must not be empty"); + } + + while (string.pointer != string.end) { + if (!IS_ALPHA(string)) { + return yaml_emitter_set_emitter_error(emitter, alias ? + "alias value must contain alphanumerical characters only" : + "anchor value must contain alphanumerical characters only"); + } + MOVE(string); + } + + emitter->anchor_data.anchor = string.start; + emitter->anchor_data.anchor_length = string.end - string.start; + emitter->anchor_data.alias = alias; + + return 1; +} + +/* + * Check if a tag is valid. + */ + +static int +yaml_emitter_analyze_tag(yaml_emitter_t *emitter, + yaml_char_t *tag) +{ + size_t tag_length; + yaml_string_t string; + yaml_tag_directive_t *tag_directive; + + tag_length = strlen((char *)tag); + STRING_ASSIGN(string, tag, tag_length); + + if (string.start == string.end) { + return yaml_emitter_set_emitter_error(emitter, + "tag value must not be empty"); + } + + for (tag_directive = emitter->tag_directives.start; + tag_directive != emitter->tag_directives.top; tag_directive ++) { + size_t prefix_length = strlen((char *)tag_directive->prefix); + if (prefix_length < (size_t)(string.end - string.start) + && strncmp((char *)tag_directive->prefix, (char *)string.start, + prefix_length) == 0) + { + emitter->tag_data.handle = tag_directive->handle; + emitter->tag_data.handle_length = + strlen((char *)tag_directive->handle); + emitter->tag_data.suffix = string.start + prefix_length; + emitter->tag_data.suffix_length = + (string.end - string.start) - prefix_length; + return 1; + } + } + + emitter->tag_data.suffix = string.start; + emitter->tag_data.suffix_length = string.end - string.start; + + return 1; +} + +/* + * Check if a scalar is valid. + */ + +static int +yaml_emitter_analyze_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length) +{ + yaml_string_t string; + + int block_indicators = 0; + int flow_indicators = 0; + int line_breaks = 0; + int special_characters = 0; + + int leading_space = 0; + int leading_break = 0; + int trailing_space = 0; + int trailing_break = 0; + int break_space = 0; + int space_break = 0; + + int preceeded_by_whitespace = 0; + int followed_by_whitespace = 0; + int previous_space = 0; + int previous_break = 0; + + STRING_ASSIGN(string, value, length); + + emitter->scalar_data.value = value; + emitter->scalar_data.length = length; + + if (string.start == string.end) + { + emitter->scalar_data.multiline = 0; + emitter->scalar_data.flow_plain_allowed = 0; + emitter->scalar_data.block_plain_allowed = 1; + emitter->scalar_data.single_quoted_allowed = 1; + emitter->scalar_data.block_allowed = 0; + + return 1; + } + + if ((CHECK_AT(string, '-', 0) + && CHECK_AT(string, '-', 1) + && CHECK_AT(string, '-', 2)) + || (CHECK_AT(string, '.', 0) + && CHECK_AT(string, '.', 1) + && CHECK_AT(string, '.', 2))) { + block_indicators = 1; + flow_indicators = 1; + } + + preceeded_by_whitespace = 1; + followed_by_whitespace = IS_BLANKZ_AT(string, WIDTH(string)); + + while (string.pointer != string.end) + { + if (string.start == string.pointer) + { + if (CHECK(string, '#') || CHECK(string, ',') + || CHECK(string, '[') || CHECK(string, ']') + || CHECK(string, '{') || CHECK(string, '}') + || CHECK(string, '&') || CHECK(string, '*') + || CHECK(string, '!') || CHECK(string, '|') + || CHECK(string, '>') || CHECK(string, '\'') + || CHECK(string, '"') || CHECK(string, '%') + || CHECK(string, '@') || CHECK(string, '`')) { + flow_indicators = 1; + block_indicators = 1; + } + + if (CHECK(string, '?') || CHECK(string, ':')) { + flow_indicators = 1; + if (followed_by_whitespace) { + block_indicators = 1; + } + } + + if (CHECK(string, '-') && followed_by_whitespace) { + flow_indicators = 1; + block_indicators = 1; + } + } + else + { + if (CHECK(string, ',') || CHECK(string, '?') + || CHECK(string, '[') || CHECK(string, ']') + || CHECK(string, '{') || CHECK(string, '}')) { + flow_indicators = 1; + } + + if (CHECK(string, ':')) { + flow_indicators = 1; + if (followed_by_whitespace) { + block_indicators = 1; + } + } + + if (CHECK(string, '#') && preceeded_by_whitespace) { + flow_indicators = 1; + block_indicators = 1; + } + } + + if (!IS_PRINTABLE(string) + || (!IS_ASCII(string) && !emitter->unicode)) { + special_characters = 1; + } + + if (IS_BREAK(string)) { + line_breaks = 1; + } + + if (IS_SPACE(string)) + { + if (string.start == string.pointer) { + leading_space = 1; + } + if (string.pointer+WIDTH(string) == string.end) { + trailing_space = 1; + } + if (previous_break) { + break_space = 1; + } + previous_space = 1; + previous_break = 0; + } + else if (IS_BREAK(string)) + { + if (string.start == string.pointer) { + leading_break = 1; + } + if (string.pointer+WIDTH(string) == string.end) { + trailing_break = 1; + } + if (previous_space) { + space_break = 1; + } + previous_space = 0; + previous_break = 1; + } + else + { + previous_space = 0; + previous_break = 0; + } + + preceeded_by_whitespace = IS_BLANKZ(string); + MOVE(string); + if (string.pointer != string.end) { + followed_by_whitespace = IS_BLANKZ_AT(string, WIDTH(string)); + } + } + + emitter->scalar_data.multiline = line_breaks; + + emitter->scalar_data.flow_plain_allowed = 1; + emitter->scalar_data.block_plain_allowed = 1; + emitter->scalar_data.single_quoted_allowed = 1; + emitter->scalar_data.block_allowed = 1; + + if (leading_space || leading_break || trailing_space || trailing_break) { + emitter->scalar_data.flow_plain_allowed = 0; + emitter->scalar_data.block_plain_allowed = 0; + } + + if (trailing_space) { + emitter->scalar_data.block_allowed = 0; + } + + if (break_space) { + emitter->scalar_data.flow_plain_allowed = 0; + emitter->scalar_data.block_plain_allowed = 0; + emitter->scalar_data.single_quoted_allowed = 0; + } + + if (space_break || special_characters) { + emitter->scalar_data.flow_plain_allowed = 0; + emitter->scalar_data.block_plain_allowed = 0; + emitter->scalar_data.single_quoted_allowed = 0; + emitter->scalar_data.block_allowed = 0; + } + + if (line_breaks) { + emitter->scalar_data.flow_plain_allowed = 0; + emitter->scalar_data.block_plain_allowed = 0; + } + + if (flow_indicators) { + emitter->scalar_data.flow_plain_allowed = 0; + } + + if (block_indicators) { + emitter->scalar_data.block_plain_allowed = 0; + } + + return 1; +} + +/* + * Check if the event data is valid. + */ + +static int +yaml_emitter_analyze_event(yaml_emitter_t *emitter, + yaml_event_t *event) +{ + emitter->anchor_data.anchor = NULL; + emitter->anchor_data.anchor_length = 0; + emitter->tag_data.handle = NULL; + emitter->tag_data.handle_length = 0; + emitter->tag_data.suffix = NULL; + emitter->tag_data.suffix_length = 0; + emitter->scalar_data.value = NULL; + emitter->scalar_data.length = 0; + + switch (event->type) + { + case YAML_ALIAS_EVENT: + if (!yaml_emitter_analyze_anchor(emitter, + event->data.alias.anchor, 1)) + return 0; + return 1; + + case YAML_SCALAR_EVENT: + if (event->data.scalar.anchor) { + if (!yaml_emitter_analyze_anchor(emitter, + event->data.scalar.anchor, 0)) + return 0; + } + if (event->data.scalar.tag && (emitter->canonical || + (!event->data.scalar.plain_implicit + && !event->data.scalar.quoted_implicit))) { + if (!yaml_emitter_analyze_tag(emitter, event->data.scalar.tag)) + return 0; + } + if (!yaml_emitter_analyze_scalar(emitter, + event->data.scalar.value, event->data.scalar.length)) + return 0; + return 1; + + case YAML_SEQUENCE_START_EVENT: + if (event->data.sequence_start.anchor) { + if (!yaml_emitter_analyze_anchor(emitter, + event->data.sequence_start.anchor, 0)) + return 0; + } + if (event->data.sequence_start.tag && (emitter->canonical || + !event->data.sequence_start.implicit)) { + if (!yaml_emitter_analyze_tag(emitter, + event->data.sequence_start.tag)) + return 0; + } + return 1; + + case YAML_MAPPING_START_EVENT: + if (event->data.mapping_start.anchor) { + if (!yaml_emitter_analyze_anchor(emitter, + event->data.mapping_start.anchor, 0)) + return 0; + } + if (event->data.mapping_start.tag && (emitter->canonical || + !event->data.mapping_start.implicit)) { + if (!yaml_emitter_analyze_tag(emitter, + event->data.mapping_start.tag)) + return 0; + } + return 1; + + default: + return 1; + } +} + +/* + * Write the BOM character. + */ + +static int +yaml_emitter_write_bom(yaml_emitter_t *emitter) +{ + if (!FLUSH(emitter)) return 0; + + *(emitter->buffer.pointer++) = (yaml_char_t) '\xEF'; + *(emitter->buffer.pointer++) = (yaml_char_t) '\xBB'; + *(emitter->buffer.pointer++) = (yaml_char_t) '\xBF'; + + return 1; +} + +static int +yaml_emitter_write_indent(yaml_emitter_t *emitter) +{ + int indent = (emitter->indent >= 0) ? emitter->indent : 0; + + if (!emitter->indention || emitter->column > indent + || (emitter->column == indent && !emitter->whitespace)) { + if (!PUT_BREAK(emitter)) return 0; + } + + while (emitter->column < indent) { + if (!PUT(emitter, ' ')) return 0; + } + + emitter->whitespace = 1; + emitter->indention = 1; + + return 1; +} + +static int +yaml_emitter_write_indicator(yaml_emitter_t *emitter, + char *indicator, int need_whitespace, + int is_whitespace, int is_indention) +{ + size_t indicator_length; + yaml_string_t string; + + indicator_length = strlen(indicator); + STRING_ASSIGN(string, (yaml_char_t *)indicator, indicator_length); + + if (need_whitespace && !emitter->whitespace) { + if (!PUT(emitter, ' ')) return 0; + } + + while (string.pointer != string.end) { + if (!WRITE(emitter, string)) return 0; + } + + emitter->whitespace = is_whitespace; + emitter->indention = (emitter->indention && is_indention); + emitter->open_ended = 0; + + return 1; +} + +static int +yaml_emitter_write_anchor(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length) +{ + yaml_string_t string; + STRING_ASSIGN(string, value, length); + + while (string.pointer != string.end) { + if (!WRITE(emitter, string)) return 0; + } + + emitter->whitespace = 0; + emitter->indention = 0; + + return 1; +} + +static int +yaml_emitter_write_tag_handle(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length) +{ + yaml_string_t string; + STRING_ASSIGN(string, value, length); + + if (!emitter->whitespace) { + if (!PUT(emitter, ' ')) return 0; + } + + while (string.pointer != string.end) { + if (!WRITE(emitter, string)) return 0; + } + + emitter->whitespace = 0; + emitter->indention = 0; + + return 1; +} + +static int +yaml_emitter_write_tag_content(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, + int need_whitespace) +{ + yaml_string_t string; + STRING_ASSIGN(string, value, length); + + if (need_whitespace && !emitter->whitespace) { + if (!PUT(emitter, ' ')) return 0; + } + + while (string.pointer != string.end) { + if (IS_ALPHA(string) + || CHECK(string, ';') || CHECK(string, '/') + || CHECK(string, '?') || CHECK(string, ':') + || CHECK(string, '@') || CHECK(string, '&') + || CHECK(string, '=') || CHECK(string, '+') + || CHECK(string, '$') || CHECK(string, ',') + || CHECK(string, '_') || CHECK(string, '.') + || CHECK(string, '~') || CHECK(string, '*') + || CHECK(string, '\'') || CHECK(string, '(') + || CHECK(string, ')') || CHECK(string, '[') + || CHECK(string, ']')) { + if (!WRITE(emitter, string)) return 0; + } + else { + int width = WIDTH(string); + unsigned int value; + while (width --) { + value = *(string.pointer++); + if (!PUT(emitter, '%')) return 0; + if (!PUT(emitter, (value >> 4) + + ((value >> 4) < 10 ? '0' : 'A' - 10))) + return 0; + if (!PUT(emitter, (value & 0x0F) + + ((value & 0x0F) < 10 ? '0' : 'A' - 10))) + return 0; + } + } + } + + emitter->whitespace = 0; + emitter->indention = 0; + + return 1; +} + +static int +yaml_emitter_write_plain_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int allow_breaks) +{ + yaml_string_t string; + int spaces = 0; + int breaks = 0; + + STRING_ASSIGN(string, value, length); + + if (!emitter->whitespace) { + if (!PUT(emitter, ' ')) return 0; + } + + while (string.pointer != string.end) + { + if (IS_SPACE(string)) + { + if (allow_breaks && !spaces + && emitter->column > emitter->best_width + && !IS_SPACE_AT(string, 1)) { + if (!yaml_emitter_write_indent(emitter)) return 0; + MOVE(string); + } + else { + if (!WRITE(emitter, string)) return 0; + } + spaces = 1; + } + else if (IS_BREAK(string)) + { + if (!breaks && CHECK(string, '\n')) { + if (!PUT_BREAK(emitter)) return 0; + } + if (!WRITE_BREAK(emitter, string)) return 0; + emitter->indention = 1; + breaks = 1; + } + else + { + if (breaks) { + if (!yaml_emitter_write_indent(emitter)) return 0; + } + if (!WRITE(emitter, string)) return 0; + emitter->indention = 0; + spaces = 0; + breaks = 0; + } + } + + emitter->whitespace = 0; + emitter->indention = 0; + if (emitter->root_context) + { + emitter->open_ended = 1; + } + + return 1; +} + +static int +yaml_emitter_write_single_quoted_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int allow_breaks) +{ + yaml_string_t string; + int spaces = 0; + int breaks = 0; + + STRING_ASSIGN(string, value, length); + + if (!yaml_emitter_write_indicator(emitter, "'", 1, 0, 0)) + return 0; + + while (string.pointer != string.end) + { + if (IS_SPACE(string)) + { + if (allow_breaks && !spaces + && emitter->column > emitter->best_width + && string.pointer != string.start + && string.pointer != string.end - 1 + && !IS_SPACE_AT(string, 1)) { + if (!yaml_emitter_write_indent(emitter)) return 0; + MOVE(string); + } + else { + if (!WRITE(emitter, string)) return 0; + } + spaces = 1; + } + else if (IS_BREAK(string)) + { + if (!breaks && CHECK(string, '\n')) { + if (!PUT_BREAK(emitter)) return 0; + } + if (!WRITE_BREAK(emitter, string)) return 0; + emitter->indention = 1; + breaks = 1; + } + else + { + if (breaks) { + if (!yaml_emitter_write_indent(emitter)) return 0; + } + if (CHECK(string, '\'')) { + if (!PUT(emitter, '\'')) return 0; + } + if (!WRITE(emitter, string)) return 0; + emitter->indention = 0; + spaces = 0; + breaks = 0; + } + } + + if (!yaml_emitter_write_indicator(emitter, "'", 0, 0, 0)) + return 0; + + emitter->whitespace = 0; + emitter->indention = 0; + + return 1; +} + +static int +yaml_emitter_write_double_quoted_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length, int allow_breaks) +{ + yaml_string_t string; + int spaces = 0; + + STRING_ASSIGN(string, value, length); + + if (!yaml_emitter_write_indicator(emitter, "\"", 1, 0, 0)) + return 0; + + while (string.pointer != string.end) + { + if (!IS_PRINTABLE(string) || (!emitter->unicode && !IS_ASCII(string)) + || IS_BOM(string) || IS_BREAK(string) + || CHECK(string, '"') || CHECK(string, '\\')) + { + unsigned char octet; + unsigned int width; + unsigned int value; + int k; + + octet = string.pointer[0]; + width = (octet & 0x80) == 0x00 ? 1 : + (octet & 0xE0) == 0xC0 ? 2 : + (octet & 0xF0) == 0xE0 ? 3 : + (octet & 0xF8) == 0xF0 ? 4 : 0; + value = (octet & 0x80) == 0x00 ? octet & 0x7F : + (octet & 0xE0) == 0xC0 ? octet & 0x1F : + (octet & 0xF0) == 0xE0 ? octet & 0x0F : + (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; + for (k = 1; k < (int)width; k ++) { + octet = string.pointer[k]; + value = (value << 6) + (octet & 0x3F); + } + string.pointer += width; + + if (!PUT(emitter, '\\')) return 0; + + switch (value) + { + case 0x00: + if (!PUT(emitter, '0')) return 0; + break; + + case 0x07: + if (!PUT(emitter, 'a')) return 0; + break; + + case 0x08: + if (!PUT(emitter, 'b')) return 0; + break; + + case 0x09: + if (!PUT(emitter, 't')) return 0; + break; + + case 0x0A: + if (!PUT(emitter, 'n')) return 0; + break; + + case 0x0B: + if (!PUT(emitter, 'v')) return 0; + break; + + case 0x0C: + if (!PUT(emitter, 'f')) return 0; + break; + + case 0x0D: + if (!PUT(emitter, 'r')) return 0; + break; + + case 0x1B: + if (!PUT(emitter, 'e')) return 0; + break; + + case 0x22: + if (!PUT(emitter, '\"')) return 0; + break; + + case 0x5C: + if (!PUT(emitter, '\\')) return 0; + break; + + case 0x85: + if (!PUT(emitter, 'N')) return 0; + break; + + case 0xA0: + if (!PUT(emitter, '_')) return 0; + break; + + case 0x2028: + if (!PUT(emitter, 'L')) return 0; + break; + + case 0x2029: + if (!PUT(emitter, 'P')) return 0; + break; + + default: + if (value <= 0xFF) { + if (!PUT(emitter, 'x')) return 0; + width = 2; + } + else if (value <= 0xFFFF) { + if (!PUT(emitter, 'u')) return 0; + width = 4; + } + else { + if (!PUT(emitter, 'U')) return 0; + width = 8; + } + for (k = (width-1)*4; k >= 0; k -= 4) { + int digit = (value >> k) & 0x0F; + if (!PUT(emitter, digit + (digit < 10 ? '0' : 'A'-10))) + return 0; + } + } + spaces = 0; + } + else if (IS_SPACE(string)) + { + if (allow_breaks && !spaces + && emitter->column > emitter->best_width + && string.pointer != string.start + && string.pointer != string.end - 1) { + if (!yaml_emitter_write_indent(emitter)) return 0; + if (IS_SPACE_AT(string, 1)) { + if (!PUT(emitter, '\\')) return 0; + } + MOVE(string); + } + else { + if (!WRITE(emitter, string)) return 0; + } + spaces = 1; + } + else + { + if (!WRITE(emitter, string)) return 0; + spaces = 0; + } + } + + if (!yaml_emitter_write_indicator(emitter, "\"", 0, 0, 0)) + return 0; + + emitter->whitespace = 0; + emitter->indention = 0; + + return 1; +} + +static int +yaml_emitter_write_block_scalar_hints(yaml_emitter_t *emitter, + yaml_string_t string) +{ + char indent_hint[2]; + char *chomp_hint = NULL; + + if (IS_SPACE(string) || IS_BREAK(string)) + { + indent_hint[0] = '0' + (char)emitter->best_indent; + indent_hint[1] = '\0'; + if (!yaml_emitter_write_indicator(emitter, indent_hint, 0, 0, 0)) + return 0; + } + + emitter->open_ended = 0; + + string.pointer = string.end; + if (string.start == string.pointer) + { + chomp_hint = "-"; + } + else + { + do { + string.pointer --; + } while ((*string.pointer & 0xC0) == 0x80); + if (!IS_BREAK(string)) + { + chomp_hint = "-"; + } + else if (string.start == string.pointer) + { + chomp_hint = "+"; + emitter->open_ended = 1; + } + else + { + do { + string.pointer --; + } while ((*string.pointer & 0xC0) == 0x80); + if (IS_BREAK(string)) + { + chomp_hint = "+"; + emitter->open_ended = 1; + } + } + } + + if (chomp_hint) + { + if (!yaml_emitter_write_indicator(emitter, chomp_hint, 0, 0, 0)) + return 0; + } + + return 1; +} + +static int +yaml_emitter_write_literal_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length) +{ + yaml_string_t string; + int breaks = 1; + + STRING_ASSIGN(string, value, length); + + if (!yaml_emitter_write_indicator(emitter, "|", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_block_scalar_hints(emitter, string)) + return 0; + if (!PUT_BREAK(emitter)) return 0; + emitter->indention = 1; + emitter->whitespace = 1; + + while (string.pointer != string.end) + { + if (IS_BREAK(string)) + { + if (!WRITE_BREAK(emitter, string)) return 0; + emitter->indention = 1; + breaks = 1; + } + else + { + if (breaks) { + if (!yaml_emitter_write_indent(emitter)) return 0; + } + if (!WRITE(emitter, string)) return 0; + emitter->indention = 0; + breaks = 0; + } + } + + return 1; +} + +static int +yaml_emitter_write_folded_scalar(yaml_emitter_t *emitter, + yaml_char_t *value, size_t length) +{ + yaml_string_t string; + int breaks = 1; + int leading_spaces = 1; + + STRING_ASSIGN(string, value, length); + + if (!yaml_emitter_write_indicator(emitter, ">", 1, 0, 0)) + return 0; + if (!yaml_emitter_write_block_scalar_hints(emitter, string)) + return 0; + if (!PUT_BREAK(emitter)) return 0; + emitter->indention = 1; + emitter->whitespace = 1; + + while (string.pointer != string.end) + { + if (IS_BREAK(string)) + { + if (!breaks && !leading_spaces && CHECK(string, '\n')) { + int k = 0; + while (IS_BREAK_AT(string, k)) { + k += WIDTH_AT(string, k); + } + if (!IS_BLANKZ_AT(string, k)) { + if (!PUT_BREAK(emitter)) return 0; + } + } + if (!WRITE_BREAK(emitter, string)) return 0; + emitter->indention = 1; + breaks = 1; + } + else + { + if (breaks) { + if (!yaml_emitter_write_indent(emitter)) return 0; + leading_spaces = IS_BLANK(string); + } + if (!breaks && IS_SPACE(string) && !IS_SPACE_AT(string, 1) + && emitter->column > emitter->best_width) { + if (!yaml_emitter_write_indent(emitter)) return 0; + MOVE(string); + } + else { + if (!WRITE(emitter, string)) return 0; + } + emitter->indention = 0; + breaks = 0; + } + } + + return 1; +} + diff --git a/src/external/yaml/loader.c b/src/external/yaml/loader.c new file mode 100644 index 0000000..871149a --- /dev/null +++ b/src/external/yaml/loader.c @@ -0,0 +1,444 @@ + +#include "yaml_private.h" + +/* + * API functions. + */ + +YAML_DECLARE(int) +yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document); + +/* + * Error handling. + */ + +static int +yaml_parser_set_composer_error(yaml_parser_t *parser, + const char *problem, yaml_mark_t problem_mark); + +static int +yaml_parser_set_composer_error_context(yaml_parser_t *parser, + const char *context, yaml_mark_t context_mark, + const char *problem, yaml_mark_t problem_mark); + + +/* + * Alias handling. + */ + +static int +yaml_parser_register_anchor(yaml_parser_t *parser, + int index, yaml_char_t *anchor); + +/* + * Clean up functions. + */ + +static void +yaml_parser_delete_aliases(yaml_parser_t *parser); + +/* + * Composer functions. + */ + +static int +yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *first_event); + +static int +yaml_parser_load_node(yaml_parser_t *parser, yaml_event_t *first_event); + +static int +yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *first_event); + +static int +yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *first_event); + +static int +yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *first_event); + +static int +yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *first_event); + +/* + * Load the next document of the stream. + */ + +YAML_DECLARE(int) +yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document) +{ + yaml_event_t event; + + assert(parser); /* Non-NULL parser object is expected. */ + assert(document); /* Non-NULL document object is expected. */ + + memset(document, 0, sizeof(yaml_document_t)); + if (!STACK_INIT(parser, document->nodes, INITIAL_STACK_SIZE)) + goto error; + + if (!parser->stream_start_produced) { + if (!yaml_parser_parse(parser, &event)) goto error; + assert(event.type == YAML_STREAM_START_EVENT); + /* STREAM-START is expected. */ + } + + if (parser->stream_end_produced) { + return 1; + } + + if (!yaml_parser_parse(parser, &event)) goto error; + if (event.type == YAML_STREAM_END_EVENT) { + return 1; + } + + if (!STACK_INIT(parser, parser->aliases, INITIAL_STACK_SIZE)) + goto error; + + parser->document = document; + + if (!yaml_parser_load_document(parser, &event)) goto error; + + yaml_parser_delete_aliases(parser); + parser->document = NULL; + + return 1; + +error: + + yaml_parser_delete_aliases(parser); + yaml_document_delete(document); + parser->document = NULL; + + return 0; +} + +/* + * Set composer error. + */ + +static int +yaml_parser_set_composer_error(yaml_parser_t *parser, + const char *problem, yaml_mark_t problem_mark) +{ + parser->error = YAML_COMPOSER_ERROR; + parser->problem = problem; + parser->problem_mark = problem_mark; + + return 0; +} + +/* + * Set composer error with context. + */ + +static int +yaml_parser_set_composer_error_context(yaml_parser_t *parser, + const char *context, yaml_mark_t context_mark, + const char *problem, yaml_mark_t problem_mark) +{ + parser->error = YAML_COMPOSER_ERROR; + parser->context = context; + parser->context_mark = context_mark; + parser->problem = problem; + parser->problem_mark = problem_mark; + + return 0; +} + +/* + * Delete the stack of aliases. + */ + +static void +yaml_parser_delete_aliases(yaml_parser_t *parser) +{ + while (!STACK_EMPTY(parser, parser->aliases)) { + yaml_free(POP(parser, parser->aliases).anchor); + } + STACK_DEL(parser, parser->aliases); +} + +/* + * Compose a document object. + */ + +static int +yaml_parser_load_document(yaml_parser_t *parser, yaml_event_t *first_event) +{ + yaml_event_t event; + + assert(first_event->type == YAML_DOCUMENT_START_EVENT); + /* DOCUMENT-START is expected. */ + + parser->document->version_directive + = first_event->data.document_start.version_directive; + parser->document->tag_directives.start + = first_event->data.document_start.tag_directives.start; + parser->document->tag_directives.end + = first_event->data.document_start.tag_directives.end; + parser->document->start_implicit + = first_event->data.document_start.implicit; + parser->document->start_mark = first_event->start_mark; + + if (!yaml_parser_parse(parser, &event)) return 0; + + if (!yaml_parser_load_node(parser, &event)) return 0; + + if (!yaml_parser_parse(parser, &event)) return 0; + assert(event.type == YAML_DOCUMENT_END_EVENT); + /* DOCUMENT-END is expected. */ + + parser->document->end_implicit = event.data.document_end.implicit; + parser->document->end_mark = event.end_mark; + + return 1; +} + +/* + * Compose a node. + */ + +static int +yaml_parser_load_node(yaml_parser_t *parser, yaml_event_t *first_event) +{ + switch (first_event->type) { + case YAML_ALIAS_EVENT: + return yaml_parser_load_alias(parser, first_event); + case YAML_SCALAR_EVENT: + return yaml_parser_load_scalar(parser, first_event); + case YAML_SEQUENCE_START_EVENT: + return yaml_parser_load_sequence(parser, first_event); + case YAML_MAPPING_START_EVENT: + return yaml_parser_load_mapping(parser, first_event); + default: + assert(0); /* Could not happen. */ + return 0; + } + + return 0; +} + +/* + * Add an anchor. + */ + +static int +yaml_parser_register_anchor(yaml_parser_t *parser, + int index, yaml_char_t *anchor) +{ + yaml_alias_data_t data; + yaml_alias_data_t *alias_data; + + if (!anchor) return 1; + + data.anchor = anchor; + data.index = index; + data.mark = parser->document->nodes.start[index-1].start_mark; + + for (alias_data = parser->aliases.start; + alias_data != parser->aliases.top; alias_data ++) { + if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) { + yaml_free(anchor); + return yaml_parser_set_composer_error_context(parser, + "found duplicate anchor; first occurence", + alias_data->mark, "second occurence", data.mark); + } + } + + if (!PUSH(parser, parser->aliases, data)) { + yaml_free(anchor); + return 0; + } + + return 1; +} + +/* + * Compose a node corresponding to an alias. + */ + +static int +yaml_parser_load_alias(yaml_parser_t *parser, yaml_event_t *first_event) +{ + yaml_char_t *anchor = first_event->data.alias.anchor; + yaml_alias_data_t *alias_data; + + for (alias_data = parser->aliases.start; + alias_data != parser->aliases.top; alias_data ++) { + if (strcmp((char *)alias_data->anchor, (char *)anchor) == 0) { + yaml_free(anchor); + return alias_data->index; + } + } + + yaml_free(anchor); + return yaml_parser_set_composer_error(parser, "found undefined alias", + first_event->start_mark); +} + +/* + * Compose a scalar node. + */ + +static int +yaml_parser_load_scalar(yaml_parser_t *parser, yaml_event_t *first_event) +{ + yaml_node_t node; + int index; + yaml_char_t *tag = first_event->data.scalar.tag; + + if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error; + + if (!tag || strcmp((char *)tag, "!") == 0) { + yaml_free(tag); + tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_SCALAR_TAG); + if (!tag) goto error; + } + + SCALAR_NODE_INIT(node, tag, first_event->data.scalar.value, + first_event->data.scalar.length, first_event->data.scalar.style, + first_event->start_mark, first_event->end_mark); + + if (!PUSH(parser, parser->document->nodes, node)) goto error; + + index = parser->document->nodes.top - parser->document->nodes.start; + + if (!yaml_parser_register_anchor(parser, index, + first_event->data.scalar.anchor)) return 0; + + return index; + +error: + yaml_free(tag); + yaml_free(first_event->data.scalar.anchor); + yaml_free(first_event->data.scalar.value); + return 0; +} + +/* + * Compose a sequence node. + */ + +static int +yaml_parser_load_sequence(yaml_parser_t *parser, yaml_event_t *first_event) +{ + yaml_event_t event; + yaml_node_t node; + struct { + yaml_node_item_t *start; + yaml_node_item_t *end; + yaml_node_item_t *top; + } items = { NULL, NULL, NULL }; + int index, item_index; + yaml_char_t *tag = first_event->data.sequence_start.tag; + + if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error; + + if (!tag || strcmp((char *)tag, "!") == 0) { + yaml_free(tag); + tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_SEQUENCE_TAG); + if (!tag) goto error; + } + + if (!STACK_INIT(parser, items, INITIAL_STACK_SIZE)) goto error; + + SEQUENCE_NODE_INIT(node, tag, items.start, items.end, + first_event->data.sequence_start.style, + first_event->start_mark, first_event->end_mark); + + if (!PUSH(parser, parser->document->nodes, node)) goto error; + + index = parser->document->nodes.top - parser->document->nodes.start; + + if (!yaml_parser_register_anchor(parser, index, + first_event->data.sequence_start.anchor)) return 0; + + if (!yaml_parser_parse(parser, &event)) return 0; + + while (event.type != YAML_SEQUENCE_END_EVENT) { + if (!STACK_LIMIT(parser, + parser->document->nodes.start[index-1].data.sequence.items, + INT_MAX-1)) return 0; + item_index = yaml_parser_load_node(parser, &event); + if (!item_index) return 0; + if (!PUSH(parser, + parser->document->nodes.start[index-1].data.sequence.items, + item_index)) return 0; + if (!yaml_parser_parse(parser, &event)) return 0; + } + + parser->document->nodes.start[index-1].end_mark = event.end_mark; + + return index; + +error: + yaml_free(tag); + yaml_free(first_event->data.sequence_start.anchor); + return 0; +} + +/* + * Compose a mapping node. + */ + +static int +yaml_parser_load_mapping(yaml_parser_t *parser, yaml_event_t *first_event) +{ + yaml_event_t event; + yaml_node_t node; + struct { + yaml_node_pair_t *start; + yaml_node_pair_t *end; + yaml_node_pair_t *top; + } pairs = { NULL, NULL, NULL }; + int index; + yaml_node_pair_t pair; + yaml_char_t *tag = first_event->data.mapping_start.tag; + + if (!STACK_LIMIT(parser, parser->document->nodes, INT_MAX-1)) goto error; + + if (!tag || strcmp((char *)tag, "!") == 0) { + yaml_free(tag); + tag = yaml_strdup((yaml_char_t *)YAML_DEFAULT_MAPPING_TAG); + if (!tag) goto error; + } + + if (!STACK_INIT(parser, pairs, INITIAL_STACK_SIZE)) goto error; + + MAPPING_NODE_INIT(node, tag, pairs.start, pairs.end, + first_event->data.mapping_start.style, + first_event->start_mark, first_event->end_mark); + + if (!PUSH(parser, parser->document->nodes, node)) goto error; + + index = parser->document->nodes.top - parser->document->nodes.start; + + if (!yaml_parser_register_anchor(parser, index, + first_event->data.mapping_start.anchor)) return 0; + + if (!yaml_parser_parse(parser, &event)) return 0; + + while (event.type != YAML_MAPPING_END_EVENT) { + if (!STACK_LIMIT(parser, + parser->document->nodes.start[index-1].data.mapping.pairs, + INT_MAX-1)) return 0; + pair.key = yaml_parser_load_node(parser, &event); + if (!pair.key) return 0; + if (!yaml_parser_parse(parser, &event)) return 0; + pair.value = yaml_parser_load_node(parser, &event); + if (!pair.value) return 0; + if (!PUSH(parser, + parser->document->nodes.start[index-1].data.mapping.pairs, + pair)) return 0; + if (!yaml_parser_parse(parser, &event)) return 0; + } + + parser->document->nodes.start[index-1].end_mark = event.end_mark; + + return index; + +error: + yaml_free(tag); + yaml_free(first_event->data.mapping_start.anchor); + return 0; +} + diff --git a/src/external/yaml/parser.c b/src/external/yaml/parser.c new file mode 100644 index 0000000..eb2a2c7 --- /dev/null +++ b/src/external/yaml/parser.c @@ -0,0 +1,1374 @@ + +/* + * The parser implements the following grammar: + * + * stream ::= STREAM-START implicit_document? explicit_document* STREAM-END + * implicit_document ::= block_node DOCUMENT-END* + * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* + * block_node_or_indentless_sequence ::= + * ALIAS + * | properties (block_content | indentless_block_sequence)? + * | block_content + * | indentless_block_sequence + * block_node ::= ALIAS + * | properties block_content? + * | block_content + * flow_node ::= ALIAS + * | properties flow_content? + * | flow_content + * properties ::= TAG ANCHOR? | ANCHOR TAG? + * block_content ::= block_collection | flow_collection | SCALAR + * flow_content ::= flow_collection | SCALAR + * block_collection ::= block_sequence | block_mapping + * flow_collection ::= flow_sequence | flow_mapping + * block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END + * indentless_sequence ::= (BLOCK-ENTRY block_node?)+ + * block_mapping ::= BLOCK-MAPPING_START + * ((KEY block_node_or_indentless_sequence?)? + * (VALUE block_node_or_indentless_sequence?)?)* + * BLOCK-END + * flow_sequence ::= FLOW-SEQUENCE-START + * (flow_sequence_entry FLOW-ENTRY)* + * flow_sequence_entry? + * FLOW-SEQUENCE-END + * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * flow_mapping ::= FLOW-MAPPING-START + * (flow_mapping_entry FLOW-ENTRY)* + * flow_mapping_entry? + * FLOW-MAPPING-END + * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + */ + +#include "yaml_private.h" + +/* + * Peek the next token in the token queue. + */ + +#define PEEK_TOKEN(parser) \ + ((parser->token_available || yaml_parser_fetch_more_tokens(parser)) ? \ + parser->tokens.head : NULL) + +/* + * Remove the next token from the queue (must be called after PEEK_TOKEN). + */ + +#define SKIP_TOKEN(parser) \ + (parser->token_available = 0, \ + parser->tokens_parsed ++, \ + parser->stream_end_produced = \ + (parser->tokens.head->type == YAML_STREAM_END_TOKEN), \ + parser->tokens.head ++) + +/* + * Public API declarations. + */ + +YAML_DECLARE(int) +yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event); + +/* + * Error handling. + */ + +static int +yaml_parser_set_parser_error(yaml_parser_t *parser, + const char *problem, yaml_mark_t problem_mark); + +static int +yaml_parser_set_parser_error_context(yaml_parser_t *parser, + const char *context, yaml_mark_t context_mark, + const char *problem, yaml_mark_t problem_mark); + +/* + * State functions. + */ + +static int +yaml_parser_state_machine(yaml_parser_t *parser, yaml_event_t *event); + +static int +yaml_parser_parse_stream_start(yaml_parser_t *parser, yaml_event_t *event); + +static int +yaml_parser_parse_document_start(yaml_parser_t *parser, yaml_event_t *event, + int implicit); + +static int +yaml_parser_parse_document_content(yaml_parser_t *parser, yaml_event_t *event); + +static int +yaml_parser_parse_document_end(yaml_parser_t *parser, yaml_event_t *event); + +static int +yaml_parser_parse_node(yaml_parser_t *parser, yaml_event_t *event, + int block, int indentless_sequence); + +static int +yaml_parser_parse_block_sequence_entry(yaml_parser_t *parser, + yaml_event_t *event, int first); + +static int +yaml_parser_parse_indentless_sequence_entry(yaml_parser_t *parser, + yaml_event_t *event); + +static int +yaml_parser_parse_block_mapping_key(yaml_parser_t *parser, + yaml_event_t *event, int first); + +static int +yaml_parser_parse_block_mapping_value(yaml_parser_t *parser, + yaml_event_t *event); + +static int +yaml_parser_parse_flow_sequence_entry(yaml_parser_t *parser, + yaml_event_t *event, int first); + +static int +yaml_parser_parse_flow_sequence_entry_mapping_key(yaml_parser_t *parser, + yaml_event_t *event); + +static int +yaml_parser_parse_flow_sequence_entry_mapping_value(yaml_parser_t *parser, + yaml_event_t *event); + +static int +yaml_parser_parse_flow_sequence_entry_mapping_end(yaml_parser_t *parser, + yaml_event_t *event); + +static int +yaml_parser_parse_flow_mapping_key(yaml_parser_t *parser, + yaml_event_t *event, int first); + +static int +yaml_parser_parse_flow_mapping_value(yaml_parser_t *parser, + yaml_event_t *event, int empty); + +/* + * Utility functions. + */ + +static int +yaml_parser_process_empty_scalar(yaml_parser_t *parser, + yaml_event_t *event, yaml_mark_t mark); + +static int +yaml_parser_process_directives(yaml_parser_t *parser, + yaml_version_directive_t **version_directive_ref, + yaml_tag_directive_t **tag_directives_start_ref, + yaml_tag_directive_t **tag_directives_end_ref); + +static int +yaml_parser_append_tag_directive(yaml_parser_t *parser, + yaml_tag_directive_t value, int allow_duplicates, yaml_mark_t mark); + +/* + * Get the next event. + */ + +YAML_DECLARE(int) +yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event) +{ + assert(parser); /* Non-NULL parser object is expected. */ + assert(event); /* Non-NULL event object is expected. */ + + /* Erase the event object. */ + + memset(event, 0, sizeof(yaml_event_t)); + + /* No events after the end of the stream or error. */ + + if (parser->stream_end_produced || parser->error || + parser->state == YAML_PARSE_END_STATE) { + return 1; + } + + /* Generate the next event. */ + + return yaml_parser_state_machine(parser, event); +} + +/* + * Set parser error. + */ + +static int +yaml_parser_set_parser_error(yaml_parser_t *parser, + const char *problem, yaml_mark_t problem_mark) +{ + parser->error = YAML_PARSER_ERROR; + parser->problem = problem; + parser->problem_mark = problem_mark; + + return 0; +} + +static int +yaml_parser_set_parser_error_context(yaml_parser_t *parser, + const char *context, yaml_mark_t context_mark, + const char *problem, yaml_mark_t problem_mark) +{ + parser->error = YAML_PARSER_ERROR; + parser->context = context; + parser->context_mark = context_mark; + parser->problem = problem; + parser->problem_mark = problem_mark; + + return 0; +} + + +/* + * State dispatcher. + */ + +static int +yaml_parser_state_machine(yaml_parser_t *parser, yaml_event_t *event) +{ + switch (parser->state) + { + case YAML_PARSE_STREAM_START_STATE: + return yaml_parser_parse_stream_start(parser, event); + + case YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE: + return yaml_parser_parse_document_start(parser, event, 1); + + case YAML_PARSE_DOCUMENT_START_STATE: + return yaml_parser_parse_document_start(parser, event, 0); + + case YAML_PARSE_DOCUMENT_CONTENT_STATE: + return yaml_parser_parse_document_content(parser, event); + + case YAML_PARSE_DOCUMENT_END_STATE: + return yaml_parser_parse_document_end(parser, event); + + case YAML_PARSE_BLOCK_NODE_STATE: + return yaml_parser_parse_node(parser, event, 1, 0); + + case YAML_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE: + return yaml_parser_parse_node(parser, event, 1, 1); + + case YAML_PARSE_FLOW_NODE_STATE: + return yaml_parser_parse_node(parser, event, 0, 0); + + case YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE: + return yaml_parser_parse_block_sequence_entry(parser, event, 1); + + case YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE: + return yaml_parser_parse_block_sequence_entry(parser, event, 0); + + case YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE: + return yaml_parser_parse_indentless_sequence_entry(parser, event); + + case YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE: + return yaml_parser_parse_block_mapping_key(parser, event, 1); + + case YAML_PARSE_BLOCK_MAPPING_KEY_STATE: + return yaml_parser_parse_block_mapping_key(parser, event, 0); + + case YAML_PARSE_BLOCK_MAPPING_VALUE_STATE: + return yaml_parser_parse_block_mapping_value(parser, event); + + case YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE: + return yaml_parser_parse_flow_sequence_entry(parser, event, 1); + + case YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE: + return yaml_parser_parse_flow_sequence_entry(parser, event, 0); + + case YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE: + return yaml_parser_parse_flow_sequence_entry_mapping_key(parser, event); + + case YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE: + return yaml_parser_parse_flow_sequence_entry_mapping_value(parser, event); + + case YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE: + return yaml_parser_parse_flow_sequence_entry_mapping_end(parser, event); + + case YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE: + return yaml_parser_parse_flow_mapping_key(parser, event, 1); + + case YAML_PARSE_FLOW_MAPPING_KEY_STATE: + return yaml_parser_parse_flow_mapping_key(parser, event, 0); + + case YAML_PARSE_FLOW_MAPPING_VALUE_STATE: + return yaml_parser_parse_flow_mapping_value(parser, event, 0); + + case YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE: + return yaml_parser_parse_flow_mapping_value(parser, event, 1); + + default: + assert(1); /* Invalid state. */ + } + + return 0; +} + +/* + * Parse the production: + * stream ::= STREAM-START implicit_document? explicit_document* STREAM-END + * ************ + */ + +static int +yaml_parser_parse_stream_start(yaml_parser_t *parser, yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type != YAML_STREAM_START_TOKEN) { + return yaml_parser_set_parser_error(parser, + "did not find expected ", token->start_mark); + } + + parser->state = YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE; + STREAM_START_EVENT_INIT(*event, token->data.stream_start.encoding, + token->start_mark, token->start_mark); + SKIP_TOKEN(parser); + + return 1; +} + +/* + * Parse the productions: + * implicit_document ::= block_node DOCUMENT-END* + * * + * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* + * ************************* + */ + +static int +yaml_parser_parse_document_start(yaml_parser_t *parser, yaml_event_t *event, + int implicit) +{ + yaml_token_t *token; + yaml_version_directive_t *version_directive = NULL; + struct { + yaml_tag_directive_t *start; + yaml_tag_directive_t *end; + } tag_directives = { NULL, NULL }; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + /* Parse extra document end indicators. */ + + if (!implicit) + { + while (token->type == YAML_DOCUMENT_END_TOKEN) { + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + } + } + + /* Parse an implicit document. */ + + if (implicit && token->type != YAML_VERSION_DIRECTIVE_TOKEN && + token->type != YAML_TAG_DIRECTIVE_TOKEN && + token->type != YAML_DOCUMENT_START_TOKEN && + token->type != YAML_STREAM_END_TOKEN) + { + if (!yaml_parser_process_directives(parser, NULL, NULL, NULL)) + return 0; + if (!PUSH(parser, parser->states, YAML_PARSE_DOCUMENT_END_STATE)) + return 0; + parser->state = YAML_PARSE_BLOCK_NODE_STATE; + DOCUMENT_START_EVENT_INIT(*event, NULL, NULL, NULL, 1, + token->start_mark, token->start_mark); + return 1; + } + + /* Parse an explicit document. */ + + else if (token->type != YAML_STREAM_END_TOKEN) + { + yaml_mark_t start_mark, end_mark; + start_mark = token->start_mark; + if (!yaml_parser_process_directives(parser, &version_directive, + &tag_directives.start, &tag_directives.end)) + return 0; + token = PEEK_TOKEN(parser); + if (!token) goto error; + if (token->type != YAML_DOCUMENT_START_TOKEN) { + yaml_parser_set_parser_error(parser, + "did not find expected ", token->start_mark); + goto error; + } + if (!PUSH(parser, parser->states, YAML_PARSE_DOCUMENT_END_STATE)) + goto error; + parser->state = YAML_PARSE_DOCUMENT_CONTENT_STATE; + end_mark = token->end_mark; + DOCUMENT_START_EVENT_INIT(*event, version_directive, + tag_directives.start, tag_directives.end, 0, + start_mark, end_mark); + SKIP_TOKEN(parser); + version_directive = NULL; + tag_directives.start = tag_directives.end = NULL; + return 1; + } + + /* Parse the stream end. */ + + else + { + parser->state = YAML_PARSE_END_STATE; + STREAM_END_EVENT_INIT(*event, token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; + } + +error: + yaml_free(version_directive); + while (tag_directives.start != tag_directives.end) { + yaml_free(tag_directives.end[-1].handle); + yaml_free(tag_directives.end[-1].prefix); + tag_directives.end --; + } + yaml_free(tag_directives.start); + return 0; +} + +/* + * Parse the productions: + * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* + * *********** + */ + +static int +yaml_parser_parse_document_content(yaml_parser_t *parser, yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_VERSION_DIRECTIVE_TOKEN || + token->type == YAML_TAG_DIRECTIVE_TOKEN || + token->type == YAML_DOCUMENT_START_TOKEN || + token->type == YAML_DOCUMENT_END_TOKEN || + token->type == YAML_STREAM_END_TOKEN) { + parser->state = POP(parser, parser->states); + return yaml_parser_process_empty_scalar(parser, event, + token->start_mark); + } + else { + return yaml_parser_parse_node(parser, event, 1, 0); + } +} + +/* + * Parse the productions: + * implicit_document ::= block_node DOCUMENT-END* + * ************* + * explicit_document ::= DIRECTIVE* DOCUMENT-START block_node? DOCUMENT-END* + * ************* + */ + +static int +yaml_parser_parse_document_end(yaml_parser_t *parser, yaml_event_t *event) +{ + yaml_token_t *token; + yaml_mark_t start_mark, end_mark; + int implicit = 1; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + start_mark = end_mark = token->start_mark; + + if (token->type == YAML_DOCUMENT_END_TOKEN) { + end_mark = token->end_mark; + SKIP_TOKEN(parser); + implicit = 0; + } + + while (!STACK_EMPTY(parser, parser->tag_directives)) { + yaml_tag_directive_t tag_directive = POP(parser, parser->tag_directives); + yaml_free(tag_directive.handle); + yaml_free(tag_directive.prefix); + } + + parser->state = YAML_PARSE_DOCUMENT_START_STATE; + DOCUMENT_END_EVENT_INIT(*event, implicit, start_mark, end_mark); + + return 1; +} + +/* + * Parse the productions: + * block_node_or_indentless_sequence ::= + * ALIAS + * ***** + * | properties (block_content | indentless_block_sequence)? + * ********** * + * | block_content | indentless_block_sequence + * * + * block_node ::= ALIAS + * ***** + * | properties block_content? + * ********** * + * | block_content + * * + * flow_node ::= ALIAS + * ***** + * | properties flow_content? + * ********** * + * | flow_content + * * + * properties ::= TAG ANCHOR? | ANCHOR TAG? + * ************************* + * block_content ::= block_collection | flow_collection | SCALAR + * ****** + * flow_content ::= flow_collection | SCALAR + * ****** + */ + +static int +yaml_parser_parse_node(yaml_parser_t *parser, yaml_event_t *event, + int block, int indentless_sequence) +{ + yaml_token_t *token; + yaml_char_t *anchor = NULL; + yaml_char_t *tag_handle = NULL; + yaml_char_t *tag_suffix = NULL; + yaml_char_t *tag = NULL; + yaml_mark_t start_mark, end_mark, tag_mark; + int implicit; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_ALIAS_TOKEN) + { + parser->state = POP(parser, parser->states); + ALIAS_EVENT_INIT(*event, token->data.alias.value, + token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; + } + + else + { + start_mark = end_mark = token->start_mark; + + if (token->type == YAML_ANCHOR_TOKEN) + { + anchor = token->data.anchor.value; + start_mark = token->start_mark; + end_mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) goto error; + if (token->type == YAML_TAG_TOKEN) + { + tag_handle = token->data.tag.handle; + tag_suffix = token->data.tag.suffix; + tag_mark = token->start_mark; + end_mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) goto error; + } + } + else if (token->type == YAML_TAG_TOKEN) + { + tag_handle = token->data.tag.handle; + tag_suffix = token->data.tag.suffix; + start_mark = tag_mark = token->start_mark; + end_mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) goto error; + if (token->type == YAML_ANCHOR_TOKEN) + { + anchor = token->data.anchor.value; + end_mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) goto error; + } + } + + if (tag_handle) { + if (!*tag_handle) { + tag = tag_suffix; + yaml_free(tag_handle); + tag_handle = tag_suffix = NULL; + } + else { + yaml_tag_directive_t *tag_directive; + for (tag_directive = parser->tag_directives.start; + tag_directive != parser->tag_directives.top; + tag_directive ++) { + if (strcmp((char *)tag_directive->handle, (char *)tag_handle) == 0) { + size_t prefix_len = strlen((char *)tag_directive->prefix); + size_t suffix_len = strlen((char *)tag_suffix); + tag = yaml_malloc(prefix_len+suffix_len+1); + if (!tag) { + parser->error = YAML_MEMORY_ERROR; + goto error; + } + memcpy(tag, tag_directive->prefix, prefix_len); + memcpy(tag+prefix_len, tag_suffix, suffix_len); + tag[prefix_len+suffix_len] = '\0'; + yaml_free(tag_handle); + yaml_free(tag_suffix); + tag_handle = tag_suffix = NULL; + break; + } + } + if (!tag) { + yaml_parser_set_parser_error_context(parser, + "while parsing a node", start_mark, + "found undefined tag handle", tag_mark); + goto error; + } + } + } + + implicit = (!tag || !*tag); + if (indentless_sequence && token->type == YAML_BLOCK_ENTRY_TOKEN) { + end_mark = token->end_mark; + parser->state = YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE; + SEQUENCE_START_EVENT_INIT(*event, anchor, tag, implicit, + YAML_BLOCK_SEQUENCE_STYLE, start_mark, end_mark); + return 1; + } + else { + if (token->type == YAML_SCALAR_TOKEN) { + int plain_implicit = 0; + int quoted_implicit = 0; + end_mark = token->end_mark; + if ((token->data.scalar.style == YAML_PLAIN_SCALAR_STYLE && !tag) + || (tag && strcmp((char *)tag, "!") == 0)) { + plain_implicit = 1; + } + else if (!tag) { + quoted_implicit = 1; + } + parser->state = POP(parser, parser->states); + SCALAR_EVENT_INIT(*event, anchor, tag, + token->data.scalar.value, token->data.scalar.length, + plain_implicit, quoted_implicit, + token->data.scalar.style, start_mark, end_mark); + SKIP_TOKEN(parser); + return 1; + } + else if (token->type == YAML_FLOW_SEQUENCE_START_TOKEN) { + end_mark = token->end_mark; + parser->state = YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE; + SEQUENCE_START_EVENT_INIT(*event, anchor, tag, implicit, + YAML_FLOW_SEQUENCE_STYLE, start_mark, end_mark); + return 1; + } + else if (token->type == YAML_FLOW_MAPPING_START_TOKEN) { + end_mark = token->end_mark; + parser->state = YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE; + MAPPING_START_EVENT_INIT(*event, anchor, tag, implicit, + YAML_FLOW_MAPPING_STYLE, start_mark, end_mark); + return 1; + } + else if (block && token->type == YAML_BLOCK_SEQUENCE_START_TOKEN) { + end_mark = token->end_mark; + parser->state = YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE; + SEQUENCE_START_EVENT_INIT(*event, anchor, tag, implicit, + YAML_BLOCK_SEQUENCE_STYLE, start_mark, end_mark); + return 1; + } + else if (block && token->type == YAML_BLOCK_MAPPING_START_TOKEN) { + end_mark = token->end_mark; + parser->state = YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE; + MAPPING_START_EVENT_INIT(*event, anchor, tag, implicit, + YAML_BLOCK_MAPPING_STYLE, start_mark, end_mark); + return 1; + } + else if (anchor || tag) { + yaml_char_t *value = yaml_malloc(1); + if (!value) { + parser->error = YAML_MEMORY_ERROR; + goto error; + } + value[0] = '\0'; + parser->state = POP(parser, parser->states); + SCALAR_EVENT_INIT(*event, anchor, tag, value, 0, + implicit, 0, YAML_PLAIN_SCALAR_STYLE, + start_mark, end_mark); + return 1; + } + else { + yaml_parser_set_parser_error_context(parser, + (block ? "while parsing a block node" + : "while parsing a flow node"), start_mark, + "did not find expected node content", token->start_mark); + goto error; + } + } + } + +error: + yaml_free(anchor); + yaml_free(tag_handle); + yaml_free(tag_suffix); + yaml_free(tag); + + return 0; +} + +/* + * Parse the productions: + * block_sequence ::= BLOCK-SEQUENCE-START (BLOCK-ENTRY block_node?)* BLOCK-END + * ******************** *********** * ********* + */ + +static int +yaml_parser_parse_block_sequence_entry(yaml_parser_t *parser, + yaml_event_t *event, int first) +{ + yaml_token_t *token; + + if (first) { + token = PEEK_TOKEN(parser); + if (!PUSH(parser, parser->marks, token->start_mark)) + return 0; + SKIP_TOKEN(parser); + } + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_BLOCK_ENTRY_TOKEN) + { + yaml_mark_t mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_BLOCK_ENTRY_TOKEN && + token->type != YAML_BLOCK_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 1, 0); + } + else { + parser->state = YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE; + return yaml_parser_process_empty_scalar(parser, event, mark); + } + } + + else if (token->type == YAML_BLOCK_END_TOKEN) + { + yaml_mark_t dummy_mark; /* Used to eliminate a compiler warning. */ + parser->state = POP(parser, parser->states); + dummy_mark = POP(parser, parser->marks); + SEQUENCE_END_EVENT_INIT(*event, token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; + } + + else + { + return yaml_parser_set_parser_error_context(parser, + "while parsing a block collection", POP(parser, parser->marks), + "did not find expected '-' indicator", token->start_mark); + } +} + +/* + * Parse the productions: + * indentless_sequence ::= (BLOCK-ENTRY block_node?)+ + * *********** * + */ + +static int +yaml_parser_parse_indentless_sequence_entry(yaml_parser_t *parser, + yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_BLOCK_ENTRY_TOKEN) + { + yaml_mark_t mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_BLOCK_ENTRY_TOKEN && + token->type != YAML_KEY_TOKEN && + token->type != YAML_VALUE_TOKEN && + token->type != YAML_BLOCK_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 1, 0); + } + else { + parser->state = YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE; + return yaml_parser_process_empty_scalar(parser, event, mark); + } + } + + else + { + parser->state = POP(parser, parser->states); + SEQUENCE_END_EVENT_INIT(*event, token->start_mark, token->start_mark); + return 1; + } +} + +/* + * Parse the productions: + * block_mapping ::= BLOCK-MAPPING_START + * ******************* + * ((KEY block_node_or_indentless_sequence?)? + * *** * + * (VALUE block_node_or_indentless_sequence?)?)* + * + * BLOCK-END + * ********* + */ + +static int +yaml_parser_parse_block_mapping_key(yaml_parser_t *parser, + yaml_event_t *event, int first) +{ + yaml_token_t *token; + + if (first) { + token = PEEK_TOKEN(parser); + if (!PUSH(parser, parser->marks, token->start_mark)) + return 0; + SKIP_TOKEN(parser); + } + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_KEY_TOKEN) + { + yaml_mark_t mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_KEY_TOKEN && + token->type != YAML_VALUE_TOKEN && + token->type != YAML_BLOCK_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_BLOCK_MAPPING_VALUE_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 1, 1); + } + else { + parser->state = YAML_PARSE_BLOCK_MAPPING_VALUE_STATE; + return yaml_parser_process_empty_scalar(parser, event, mark); + } + } + + else if (token->type == YAML_BLOCK_END_TOKEN) + { + yaml_mark_t dummy_mark; /* Used to eliminate a compiler warning. */ + parser->state = POP(parser, parser->states); + dummy_mark = POP(parser, parser->marks); + MAPPING_END_EVENT_INIT(*event, token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; + } + + else + { + return yaml_parser_set_parser_error_context(parser, + "while parsing a block mapping", POP(parser, parser->marks), + "did not find expected key", token->start_mark); + } +} + +/* + * Parse the productions: + * block_mapping ::= BLOCK-MAPPING_START + * + * ((KEY block_node_or_indentless_sequence?)? + * + * (VALUE block_node_or_indentless_sequence?)?)* + * ***** * + * BLOCK-END + * + */ + +static int +yaml_parser_parse_block_mapping_value(yaml_parser_t *parser, + yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_VALUE_TOKEN) + { + yaml_mark_t mark = token->end_mark; + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_KEY_TOKEN && + token->type != YAML_VALUE_TOKEN && + token->type != YAML_BLOCK_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_BLOCK_MAPPING_KEY_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 1, 1); + } + else { + parser->state = YAML_PARSE_BLOCK_MAPPING_KEY_STATE; + return yaml_parser_process_empty_scalar(parser, event, mark); + } + } + + else + { + parser->state = YAML_PARSE_BLOCK_MAPPING_KEY_STATE; + return yaml_parser_process_empty_scalar(parser, event, token->start_mark); + } +} + +/* + * Parse the productions: + * flow_sequence ::= FLOW-SEQUENCE-START + * ******************* + * (flow_sequence_entry FLOW-ENTRY)* + * * ********** + * flow_sequence_entry? + * * + * FLOW-SEQUENCE-END + * ***************** + * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * * + */ + +static int +yaml_parser_parse_flow_sequence_entry(yaml_parser_t *parser, + yaml_event_t *event, int first) +{ + yaml_token_t *token; + yaml_mark_t dummy_mark; /* Used to eliminate a compiler warning. */ + + if (first) { + token = PEEK_TOKEN(parser); + if (!PUSH(parser, parser->marks, token->start_mark)) + return 0; + SKIP_TOKEN(parser); + } + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type != YAML_FLOW_SEQUENCE_END_TOKEN) + { + if (!first) { + if (token->type == YAML_FLOW_ENTRY_TOKEN) { + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + } + else { + return yaml_parser_set_parser_error_context(parser, + "while parsing a flow sequence", POP(parser, parser->marks), + "did not find expected ',' or ']'", token->start_mark); + } + } + + if (token->type == YAML_KEY_TOKEN) { + parser->state = YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE; + MAPPING_START_EVENT_INIT(*event, NULL, NULL, + 1, YAML_FLOW_MAPPING_STYLE, + token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; + } + + else if (token->type != YAML_FLOW_SEQUENCE_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 0, 0); + } + } + + parser->state = POP(parser, parser->states); + dummy_mark = POP(parser, parser->marks); + SEQUENCE_END_EVENT_INIT(*event, token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; +} + +/* + * Parse the productions: + * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * *** * + */ + +static int +yaml_parser_parse_flow_sequence_entry_mapping_key(yaml_parser_t *parser, + yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type != YAML_VALUE_TOKEN && token->type != YAML_FLOW_ENTRY_TOKEN + && token->type != YAML_FLOW_SEQUENCE_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 0, 0); + } + else { + yaml_mark_t mark = token->end_mark; + SKIP_TOKEN(parser); + parser->state = YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE; + return yaml_parser_process_empty_scalar(parser, event, mark); + } +} + +/* + * Parse the productions: + * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * ***** * + */ + +static int +yaml_parser_parse_flow_sequence_entry_mapping_value(yaml_parser_t *parser, + yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type == YAML_VALUE_TOKEN) { + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_FLOW_ENTRY_TOKEN + && token->type != YAML_FLOW_SEQUENCE_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 0, 0); + } + } + parser->state = YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE; + return yaml_parser_process_empty_scalar(parser, event, token->start_mark); +} + +/* + * Parse the productions: + * flow_sequence_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * * + */ + +static int +yaml_parser_parse_flow_sequence_entry_mapping_end(yaml_parser_t *parser, + yaml_event_t *event) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + parser->state = YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE; + + MAPPING_END_EVENT_INIT(*event, token->start_mark, token->start_mark); + return 1; +} + +/* + * Parse the productions: + * flow_mapping ::= FLOW-MAPPING-START + * ****************** + * (flow_mapping_entry FLOW-ENTRY)* + * * ********** + * flow_mapping_entry? + * ****************** + * FLOW-MAPPING-END + * **************** + * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * * *** * + */ + +static int +yaml_parser_parse_flow_mapping_key(yaml_parser_t *parser, + yaml_event_t *event, int first) +{ + yaml_token_t *token; + yaml_mark_t dummy_mark; /* Used to eliminate a compiler warning. */ + + if (first) { + token = PEEK_TOKEN(parser); + if (!PUSH(parser, parser->marks, token->start_mark)) + return 0; + SKIP_TOKEN(parser); + } + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (token->type != YAML_FLOW_MAPPING_END_TOKEN) + { + if (!first) { + if (token->type == YAML_FLOW_ENTRY_TOKEN) { + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + } + else { + return yaml_parser_set_parser_error_context(parser, + "while parsing a flow mapping", POP(parser, parser->marks), + "did not find expected ',' or '}'", token->start_mark); + } + } + + if (token->type == YAML_KEY_TOKEN) { + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_VALUE_TOKEN + && token->type != YAML_FLOW_ENTRY_TOKEN + && token->type != YAML_FLOW_MAPPING_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_FLOW_MAPPING_VALUE_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 0, 0); + } + else { + parser->state = YAML_PARSE_FLOW_MAPPING_VALUE_STATE; + return yaml_parser_process_empty_scalar(parser, event, + token->start_mark); + } + } + else if (token->type != YAML_FLOW_MAPPING_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 0, 0); + } + } + + parser->state = POP(parser, parser->states); + dummy_mark = POP(parser, parser->marks); + MAPPING_END_EVENT_INIT(*event, token->start_mark, token->end_mark); + SKIP_TOKEN(parser); + return 1; +} + +/* + * Parse the productions: + * flow_mapping_entry ::= flow_node | KEY flow_node? (VALUE flow_node?)? + * * ***** * + */ + +static int +yaml_parser_parse_flow_mapping_value(yaml_parser_t *parser, + yaml_event_t *event, int empty) +{ + yaml_token_t *token; + + token = PEEK_TOKEN(parser); + if (!token) return 0; + + if (empty) { + parser->state = YAML_PARSE_FLOW_MAPPING_KEY_STATE; + return yaml_parser_process_empty_scalar(parser, event, + token->start_mark); + } + + if (token->type == YAML_VALUE_TOKEN) { + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) return 0; + if (token->type != YAML_FLOW_ENTRY_TOKEN + && token->type != YAML_FLOW_MAPPING_END_TOKEN) { + if (!PUSH(parser, parser->states, + YAML_PARSE_FLOW_MAPPING_KEY_STATE)) + return 0; + return yaml_parser_parse_node(parser, event, 0, 0); + } + } + + parser->state = YAML_PARSE_FLOW_MAPPING_KEY_STATE; + return yaml_parser_process_empty_scalar(parser, event, token->start_mark); +} + +/* + * Generate an empty scalar event. + */ + +static int +yaml_parser_process_empty_scalar(yaml_parser_t *parser, yaml_event_t *event, + yaml_mark_t mark) +{ + yaml_char_t *value; + + value = yaml_malloc(1); + if (!value) { + parser->error = YAML_MEMORY_ERROR; + return 0; + } + value[0] = '\0'; + + SCALAR_EVENT_INIT(*event, NULL, NULL, value, 0, + 1, 0, YAML_PLAIN_SCALAR_STYLE, mark, mark); + + return 1; +} + +/* + * Parse directives. + */ + +static int +yaml_parser_process_directives(yaml_parser_t *parser, + yaml_version_directive_t **version_directive_ref, + yaml_tag_directive_t **tag_directives_start_ref, + yaml_tag_directive_t **tag_directives_end_ref) +{ + yaml_tag_directive_t default_tag_directives[] = { + {(yaml_char_t *)"!", (yaml_char_t *)"!"}, + {(yaml_char_t *)"!!", (yaml_char_t *)"tag:yaml.org,2002:"}, + {NULL, NULL} + }; + yaml_tag_directive_t *default_tag_directive; + yaml_version_directive_t *version_directive = NULL; + struct { + yaml_tag_directive_t *start; + yaml_tag_directive_t *end; + yaml_tag_directive_t *top; + } tag_directives = { NULL, NULL, NULL }; + yaml_token_t *token; + + if (!STACK_INIT(parser, tag_directives, INITIAL_STACK_SIZE)) + goto error; + + token = PEEK_TOKEN(parser); + if (!token) goto error; + + while (token->type == YAML_VERSION_DIRECTIVE_TOKEN || + token->type == YAML_TAG_DIRECTIVE_TOKEN) + { + if (token->type == YAML_VERSION_DIRECTIVE_TOKEN) { + if (version_directive) { + yaml_parser_set_parser_error(parser, + "found duplicate %YAML directive", token->start_mark); + goto error; + } + if (token->data.version_directive.major != 1 + || token->data.version_directive.minor != 1) { + yaml_parser_set_parser_error(parser, + "found incompatible YAML document", token->start_mark); + goto error; + } + version_directive = yaml_malloc(sizeof(yaml_version_directive_t)); + if (!version_directive) { + parser->error = YAML_MEMORY_ERROR; + goto error; + } + version_directive->major = token->data.version_directive.major; + version_directive->minor = token->data.version_directive.minor; + } + + else if (token->type == YAML_TAG_DIRECTIVE_TOKEN) { + yaml_tag_directive_t value; + value.handle = token->data.tag_directive.handle; + value.prefix = token->data.tag_directive.prefix; + + if (!yaml_parser_append_tag_directive(parser, value, 0, + token->start_mark)) + goto error; + if (!PUSH(parser, tag_directives, value)) + goto error; + } + + SKIP_TOKEN(parser); + token = PEEK_TOKEN(parser); + if (!token) goto error; + } + + for (default_tag_directive = default_tag_directives; + default_tag_directive->handle; default_tag_directive++) { + if (!yaml_parser_append_tag_directive(parser, *default_tag_directive, 1, + token->start_mark)) + goto error; + } + + if (version_directive_ref) { + *version_directive_ref = version_directive; + } + if (tag_directives_start_ref) { + if (STACK_EMPTY(parser, tag_directives)) { + *tag_directives_start_ref = *tag_directives_end_ref = NULL; + STACK_DEL(parser, tag_directives); + } + else { + *tag_directives_start_ref = tag_directives.start; + *tag_directives_end_ref = tag_directives.top; + } + } + else { + STACK_DEL(parser, tag_directives); + } + + return 1; + +error: + yaml_free(version_directive); + while (!STACK_EMPTY(parser, tag_directives)) { + yaml_tag_directive_t tag_directive = POP(parser, tag_directives); + yaml_free(tag_directive.handle); + yaml_free(tag_directive.prefix); + } + STACK_DEL(parser, tag_directives); + return 0; +} + +/* + * Append a tag directive to the directives stack. + */ + +static int +yaml_parser_append_tag_directive(yaml_parser_t *parser, + yaml_tag_directive_t value, int allow_duplicates, yaml_mark_t mark) +{ + yaml_tag_directive_t *tag_directive; + yaml_tag_directive_t copy = { NULL, NULL }; + + for (tag_directive = parser->tag_directives.start; + tag_directive != parser->tag_directives.top; tag_directive ++) { + if (strcmp((char *)value.handle, (char *)tag_directive->handle) == 0) { + if (allow_duplicates) + return 1; + return yaml_parser_set_parser_error(parser, + "found duplicate %TAG directive", mark); + } + } + + copy.handle = yaml_strdup(value.handle); + copy.prefix = yaml_strdup(value.prefix); + if (!copy.handle || !copy.prefix) { + parser->error = YAML_MEMORY_ERROR; + goto error; + } + + if (!PUSH(parser, parser->tag_directives, copy)) + goto error; + + return 1; + +error: + yaml_free(copy.handle); + yaml_free(copy.prefix); + return 0; +} + diff --git a/src/external/yaml/reader.c b/src/external/yaml/reader.c new file mode 100644 index 0000000..d47921c --- /dev/null +++ b/src/external/yaml/reader.c @@ -0,0 +1,469 @@ + +#include "yaml_private.h" + +/* + * Declarations. + */ + +static int +yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem, + size_t offset, int value); + +static int +yaml_parser_update_raw_buffer(yaml_parser_t *parser); + +static int +yaml_parser_determine_encoding(yaml_parser_t *parser); + +YAML_DECLARE(int) +yaml_parser_update_buffer(yaml_parser_t *parser, size_t length); + +/* + * Set the reader error and return 0. + */ + +static int +yaml_parser_set_reader_error(yaml_parser_t *parser, const char *problem, + size_t offset, int value) +{ + parser->error = YAML_READER_ERROR; + parser->problem = problem; + parser->problem_offset = offset; + parser->problem_value = value; + + return 0; +} + +/* + * Byte order marks. + */ + +#define BOM_UTF8 "\xef\xbb\xbf" +#define BOM_UTF16LE "\xff\xfe" +#define BOM_UTF16BE "\xfe\xff" + +/* + * Determine the input stream encoding by checking the BOM symbol. If no BOM is + * found, the UTF-8 encoding is assumed. Return 1 on success, 0 on failure. + */ + +static int +yaml_parser_determine_encoding(yaml_parser_t *parser) +{ + /* Ensure that we had enough bytes in the raw buffer. */ + + while (!parser->eof + && parser->raw_buffer.last - parser->raw_buffer.pointer < 3) { + if (!yaml_parser_update_raw_buffer(parser)) { + return 0; + } + } + + /* Determine the encoding. */ + + if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 2 + && !memcmp(parser->raw_buffer.pointer, BOM_UTF16LE, 2)) { + parser->encoding = YAML_UTF16LE_ENCODING; + parser->raw_buffer.pointer += 2; + parser->offset += 2; + } + else if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 2 + && !memcmp(parser->raw_buffer.pointer, BOM_UTF16BE, 2)) { + parser->encoding = YAML_UTF16BE_ENCODING; + parser->raw_buffer.pointer += 2; + parser->offset += 2; + } + else if (parser->raw_buffer.last - parser->raw_buffer.pointer >= 3 + && !memcmp(parser->raw_buffer.pointer, BOM_UTF8, 3)) { + parser->encoding = YAML_UTF8_ENCODING; + parser->raw_buffer.pointer += 3; + parser->offset += 3; + } + else { + parser->encoding = YAML_UTF8_ENCODING; + } + + return 1; +} + +/* + * Update the raw buffer. + */ + +static int +yaml_parser_update_raw_buffer(yaml_parser_t *parser) +{ + size_t size_read = 0; + + /* Return if the raw buffer is full. */ + + if (parser->raw_buffer.start == parser->raw_buffer.pointer + && parser->raw_buffer.last == parser->raw_buffer.end) + return 1; + + /* Return on EOF. */ + + if (parser->eof) return 1; + + /* Move the remaining bytes in the raw buffer to the beginning. */ + + if (parser->raw_buffer.start < parser->raw_buffer.pointer + && parser->raw_buffer.pointer < parser->raw_buffer.last) { + memmove(parser->raw_buffer.start, parser->raw_buffer.pointer, + parser->raw_buffer.last - parser->raw_buffer.pointer); + } + parser->raw_buffer.last -= + parser->raw_buffer.pointer - parser->raw_buffer.start; + parser->raw_buffer.pointer = parser->raw_buffer.start; + + /* Call the read handler to fill the buffer. */ + + if (!parser->read_handler(parser->read_handler_data, parser->raw_buffer.last, + parser->raw_buffer.end - parser->raw_buffer.last, &size_read)) { + return yaml_parser_set_reader_error(parser, "input error", + parser->offset, -1); + } + parser->raw_buffer.last += size_read; + if (!size_read) { + parser->eof = 1; + } + + return 1; +} + +/* + * Ensure that the buffer contains at least `length` characters. + * Return 1 on success, 0 on failure. + * + * The length is supposed to be significantly less that the buffer size. + */ + +YAML_DECLARE(int) +yaml_parser_update_buffer(yaml_parser_t *parser, size_t length) +{ + int first = 1; + + assert(parser->read_handler); /* Read handler must be set. */ + + /* If the EOF flag is set and the raw buffer is empty, do nothing. */ + + if (parser->eof && parser->raw_buffer.pointer == parser->raw_buffer.last) + return 1; + + /* Return if the buffer contains enough characters. */ + + if (parser->unread >= length) + return 1; + + /* Determine the input encoding if it is not known yet. */ + + if (!parser->encoding) { + if (!yaml_parser_determine_encoding(parser)) + return 0; + } + + /* Move the unread characters to the beginning of the buffer. */ + + if (parser->buffer.start < parser->buffer.pointer + && parser->buffer.pointer < parser->buffer.last) { + size_t size = parser->buffer.last - parser->buffer.pointer; + memmove(parser->buffer.start, parser->buffer.pointer, size); + parser->buffer.pointer = parser->buffer.start; + parser->buffer.last = parser->buffer.start + size; + } + else if (parser->buffer.pointer == parser->buffer.last) { + parser->buffer.pointer = parser->buffer.start; + parser->buffer.last = parser->buffer.start; + } + + /* Fill the buffer until it has enough characters. */ + + while (parser->unread < length) + { + /* Fill the raw buffer if necessary. */ + + if (!first || parser->raw_buffer.pointer == parser->raw_buffer.last) { + if (!yaml_parser_update_raw_buffer(parser)) return 0; + } + first = 0; + + /* Decode the raw buffer. */ + + while (parser->raw_buffer.pointer != parser->raw_buffer.last) + { + unsigned int value = 0, value2 = 0; + int incomplete = 0; + unsigned char octet; + unsigned int width = 0; + int low, high; + size_t k; + size_t raw_unread = parser->raw_buffer.last - parser->raw_buffer.pointer; + + /* Decode the next character. */ + + switch (parser->encoding) + { + case YAML_UTF8_ENCODING: + + /* + * Decode a UTF-8 character. Check RFC 3629 + * (http://www.ietf.org/rfc/rfc3629.txt) for more details. + * + * The following table (taken from the RFC) is used for + * decoding. + * + * Char. number range | UTF-8 octet sequence + * (hexadecimal) | (binary) + * --------------------+------------------------------------ + * 0000 0000-0000 007F | 0xxxxxxx + * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx + * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx + * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + * + * Additionally, the characters in the range 0xD800-0xDFFF + * are prohibited as they are reserved for use with UTF-16 + * surrogate pairs. + */ + + /* Determine the length of the UTF-8 sequence. */ + + octet = parser->raw_buffer.pointer[0]; + width = (octet & 0x80) == 0x00 ? 1 : + (octet & 0xE0) == 0xC0 ? 2 : + (octet & 0xF0) == 0xE0 ? 3 : + (octet & 0xF8) == 0xF0 ? 4 : 0; + + /* Check if the leading octet is valid. */ + + if (!width) + return yaml_parser_set_reader_error(parser, + "invalid leading UTF-8 octet", + parser->offset, octet); + + /* Check if the raw buffer contains an incomplete character. */ + + if (width > raw_unread) { + if (parser->eof) { + return yaml_parser_set_reader_error(parser, + "incomplete UTF-8 octet sequence", + parser->offset, -1); + } + incomplete = 1; + break; + } + + /* Decode the leading octet. */ + + value = (octet & 0x80) == 0x00 ? octet & 0x7F : + (octet & 0xE0) == 0xC0 ? octet & 0x1F : + (octet & 0xF0) == 0xE0 ? octet & 0x0F : + (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; + + /* Check and decode the trailing octets. */ + + for (k = 1; k < width; k ++) + { + octet = parser->raw_buffer.pointer[k]; + + /* Check if the octet is valid. */ + + if ((octet & 0xC0) != 0x80) + return yaml_parser_set_reader_error(parser, + "invalid trailing UTF-8 octet", + parser->offset+k, octet); + + /* Decode the octet. */ + + value = (value << 6) + (octet & 0x3F); + } + + /* Check the length of the sequence against the value. */ + + if (!((width == 1) || + (width == 2 && value >= 0x80) || + (width == 3 && value >= 0x800) || + (width == 4 && value >= 0x10000))) + return yaml_parser_set_reader_error(parser, + "invalid length of a UTF-8 sequence", + parser->offset, -1); + + /* Check the range of the value. */ + + if ((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) + return yaml_parser_set_reader_error(parser, + "invalid Unicode character", + parser->offset, value); + + break; + + case YAML_UTF16LE_ENCODING: + case YAML_UTF16BE_ENCODING: + + low = (parser->encoding == YAML_UTF16LE_ENCODING ? 0 : 1); + high = (parser->encoding == YAML_UTF16LE_ENCODING ? 1 : 0); + + /* + * The UTF-16 encoding is not as simple as one might + * naively think. Check RFC 2781 + * (http://www.ietf.org/rfc/rfc2781.txt). + * + * Normally, two subsequent bytes describe a Unicode + * character. However a special technique (called a + * surrogate pair) is used for specifying character + * values larger than 0xFFFF. + * + * A surrogate pair consists of two pseudo-characters: + * high surrogate area (0xD800-0xDBFF) + * low surrogate area (0xDC00-0xDFFF) + * + * The following formulas are used for decoding + * and encoding characters using surrogate pairs: + * + * U = U' + 0x10000 (0x01 00 00 <= U <= 0x10 FF FF) + * U' = yyyyyyyyyyxxxxxxxxxx (0 <= U' <= 0x0F FF FF) + * W1 = 110110yyyyyyyyyy + * W2 = 110111xxxxxxxxxx + * + * where U is the character value, W1 is the high surrogate + * area, W2 is the low surrogate area. + */ + + /* Check for incomplete UTF-16 character. */ + + if (raw_unread < 2) { + if (parser->eof) { + return yaml_parser_set_reader_error(parser, + "incomplete UTF-16 character", + parser->offset, -1); + } + incomplete = 1; + break; + } + + /* Get the character. */ + + value = parser->raw_buffer.pointer[low] + + (parser->raw_buffer.pointer[high] << 8); + + /* Check for unexpected low surrogate area. */ + + if ((value & 0xFC00) == 0xDC00) + return yaml_parser_set_reader_error(parser, + "unexpected low surrogate area", + parser->offset, value); + + /* Check for a high surrogate area. */ + + if ((value & 0xFC00) == 0xD800) { + + width = 4; + + /* Check for incomplete surrogate pair. */ + + if (raw_unread < 4) { + if (parser->eof) { + return yaml_parser_set_reader_error(parser, + "incomplete UTF-16 surrogate pair", + parser->offset, -1); + } + incomplete = 1; + break; + } + + /* Get the next character. */ + + value2 = parser->raw_buffer.pointer[low+2] + + (parser->raw_buffer.pointer[high+2] << 8); + + /* Check for a low surrogate area. */ + + if ((value2 & 0xFC00) != 0xDC00) + return yaml_parser_set_reader_error(parser, + "expected low surrogate area", + parser->offset+2, value2); + + /* Generate the value of the surrogate pair. */ + + value = 0x10000 + ((value & 0x3FF) << 10) + (value2 & 0x3FF); + } + + else { + width = 2; + } + + break; + + default: + assert(1); /* Impossible. */ + } + + /* Check if the raw buffer contains enough bytes to form a character. */ + + if (incomplete) break; + + /* + * Check if the character is in the allowed range: + * #x9 | #xA | #xD | [#x20-#x7E] (8 bit) + * | #x85 | [#xA0-#xD7FF] | [#xE000-#xFFFD] (16 bit) + * | [#x10000-#x10FFFF] (32 bit) + */ + + if (! (value == 0x09 || value == 0x0A || value == 0x0D + || (value >= 0x20 && value <= 0x7E) + || (value == 0x85) || (value >= 0xA0 && value <= 0xD7FF) + || (value >= 0xE000 && value <= 0xFFFD) + || (value >= 0x10000 && value <= 0x10FFFF))) + return yaml_parser_set_reader_error(parser, + "control characters are not allowed", + parser->offset, value); + + /* Move the raw pointers. */ + + parser->raw_buffer.pointer += width; + parser->offset += width; + + /* Finally put the character into the buffer. */ + + /* 0000 0000-0000 007F -> 0xxxxxxx */ + if (value <= 0x7F) { + *(parser->buffer.last++) = value; + } + /* 0000 0080-0000 07FF -> 110xxxxx 10xxxxxx */ + else if (value <= 0x7FF) { + *(parser->buffer.last++) = 0xC0 + (value >> 6); + *(parser->buffer.last++) = 0x80 + (value & 0x3F); + } + /* 0000 0800-0000 FFFF -> 1110xxxx 10xxxxxx 10xxxxxx */ + else if (value <= 0xFFFF) { + *(parser->buffer.last++) = 0xE0 + (value >> 12); + *(parser->buffer.last++) = 0x80 + ((value >> 6) & 0x3F); + *(parser->buffer.last++) = 0x80 + (value & 0x3F); + } + /* 0001 0000-0010 FFFF -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + else { + *(parser->buffer.last++) = 0xF0 + (value >> 18); + *(parser->buffer.last++) = 0x80 + ((value >> 12) & 0x3F); + *(parser->buffer.last++) = 0x80 + ((value >> 6) & 0x3F); + *(parser->buffer.last++) = 0x80 + (value & 0x3F); + } + + parser->unread ++; + } + + /* On EOF, put NUL into the buffer and return. */ + + if (parser->eof) { + *(parser->buffer.last++) = '\0'; + parser->unread ++; + return 1; + } + + } + + if (parser->offset >= PTRDIFF_MAX) + return yaml_parser_set_reader_error(parser, "input is too long", + PTRDIFF_MAX, -1); + + return 1; +} + diff --git a/src/external/yaml/scanner.c b/src/external/yaml/scanner.c new file mode 100644 index 0000000..5ec0be0 --- /dev/null +++ b/src/external/yaml/scanner.c @@ -0,0 +1,3576 @@ + +/* + * Introduction + * ************ + * + * The following notes assume that you are familiar with the YAML specification + * (http://yaml.org/spec/cvs/current.html). We mostly follow it, although in + * some cases we are less restrictive that it requires. + * + * The process of transforming a YAML stream into a sequence of events is + * divided on two steps: Scanning and Parsing. + * + * The Scanner transforms the input stream into a sequence of tokens, while the + * parser transform the sequence of tokens produced by the Scanner into a + * sequence of parsing events. + * + * The Scanner is rather clever and complicated. The Parser, on the contrary, + * is a straightforward implementation of a recursive-descendant parser (or, + * LL(1) parser, as it is usually called). + * + * Actually there are two issues of Scanning that might be called "clever", the + * rest is quite straightforward. The issues are "block collection start" and + * "simple keys". Both issues are explained below in details. + * + * Here the Scanning step is explained and implemented. We start with the list + * of all the tokens produced by the Scanner together with short descriptions. + * + * Now, tokens: + * + * STREAM-START(encoding) # The stream start. + * STREAM-END # The stream end. + * VERSION-DIRECTIVE(major,minor) # The '%YAML' directive. + * TAG-DIRECTIVE(handle,prefix) # The '%TAG' directive. + * DOCUMENT-START # '---' + * DOCUMENT-END # '...' + * BLOCK-SEQUENCE-START # Indentation increase denoting a block + * BLOCK-MAPPING-START # sequence or a block mapping. + * BLOCK-END # Indentation decrease. + * FLOW-SEQUENCE-START # '[' + * FLOW-SEQUENCE-END # ']' + * BLOCK-SEQUENCE-START # '{' + * BLOCK-SEQUENCE-END # '}' + * BLOCK-ENTRY # '-' + * FLOW-ENTRY # ',' + * KEY # '?' or nothing (simple keys). + * VALUE # ':' + * ALIAS(anchor) # '*anchor' + * ANCHOR(anchor) # '&anchor' + * TAG(handle,suffix) # '!handle!suffix' + * SCALAR(value,style) # A scalar. + * + * The following two tokens are "virtual" tokens denoting the beginning and the + * end of the stream: + * + * STREAM-START(encoding) + * STREAM-END + * + * We pass the information about the input stream encoding with the + * STREAM-START token. + * + * The next two tokens are responsible for tags: + * + * VERSION-DIRECTIVE(major,minor) + * TAG-DIRECTIVE(handle,prefix) + * + * Example: + * + * %YAML 1.1 + * %TAG ! !foo + * %TAG !yaml! tag:yaml.org,2002: + * --- + * + * The correspoding sequence of tokens: + * + * STREAM-START(utf-8) + * VERSION-DIRECTIVE(1,1) + * TAG-DIRECTIVE("!","!foo") + * TAG-DIRECTIVE("!yaml","tag:yaml.org,2002:") + * DOCUMENT-START + * STREAM-END + * + * Note that the VERSION-DIRECTIVE and TAG-DIRECTIVE tokens occupy a whole + * line. + * + * The document start and end indicators are represented by: + * + * DOCUMENT-START + * DOCUMENT-END + * + * Note that if a YAML stream contains an implicit document (without '---' + * and '...' indicators), no DOCUMENT-START and DOCUMENT-END tokens will be + * produced. + * + * In the following examples, we present whole documents together with the + * produced tokens. + * + * 1. An implicit document: + * + * 'a scalar' + * + * Tokens: + * + * STREAM-START(utf-8) + * SCALAR("a scalar",single-quoted) + * STREAM-END + * + * 2. An explicit document: + * + * --- + * 'a scalar' + * ... + * + * Tokens: + * + * STREAM-START(utf-8) + * DOCUMENT-START + * SCALAR("a scalar",single-quoted) + * DOCUMENT-END + * STREAM-END + * + * 3. Several documents in a stream: + * + * 'a scalar' + * --- + * 'another scalar' + * --- + * 'yet another scalar' + * + * Tokens: + * + * STREAM-START(utf-8) + * SCALAR("a scalar",single-quoted) + * DOCUMENT-START + * SCALAR("another scalar",single-quoted) + * DOCUMENT-START + * SCALAR("yet another scalar",single-quoted) + * STREAM-END + * + * We have already introduced the SCALAR token above. The following tokens are + * used to describe aliases, anchors, tag, and scalars: + * + * ALIAS(anchor) + * ANCHOR(anchor) + * TAG(handle,suffix) + * SCALAR(value,style) + * + * The following series of examples illustrate the usage of these tokens: + * + * 1. A recursive sequence: + * + * &A [ *A ] + * + * Tokens: + * + * STREAM-START(utf-8) + * ANCHOR("A") + * FLOW-SEQUENCE-START + * ALIAS("A") + * FLOW-SEQUENCE-END + * STREAM-END + * + * 2. A tagged scalar: + * + * !!float "3.14" # A good approximation. + * + * Tokens: + * + * STREAM-START(utf-8) + * TAG("!!","float") + * SCALAR("3.14",double-quoted) + * STREAM-END + * + * 3. Various scalar styles: + * + * --- # Implicit empty plain scalars do not produce tokens. + * --- a plain scalar + * --- 'a single-quoted scalar' + * --- "a double-quoted scalar" + * --- |- + * a literal scalar + * --- >- + * a folded + * scalar + * + * Tokens: + * + * STREAM-START(utf-8) + * DOCUMENT-START + * DOCUMENT-START + * SCALAR("a plain scalar",plain) + * DOCUMENT-START + * SCALAR("a single-quoted scalar",single-quoted) + * DOCUMENT-START + * SCALAR("a double-quoted scalar",double-quoted) + * DOCUMENT-START + * SCALAR("a literal scalar",literal) + * DOCUMENT-START + * SCALAR("a folded scalar",folded) + * STREAM-END + * + * Now it's time to review collection-related tokens. We will start with + * flow collections: + * + * FLOW-SEQUENCE-START + * FLOW-SEQUENCE-END + * FLOW-MAPPING-START + * FLOW-MAPPING-END + * FLOW-ENTRY + * KEY + * VALUE + * + * The tokens FLOW-SEQUENCE-START, FLOW-SEQUENCE-END, FLOW-MAPPING-START, and + * FLOW-MAPPING-END represent the indicators '[', ']', '{', and '}' + * correspondingly. FLOW-ENTRY represent the ',' indicator. Finally the + * indicators '?' and ':', which are used for denoting mapping keys and values, + * are represented by the KEY and VALUE tokens. + * + * The following examples show flow collections: + * + * 1. A flow sequence: + * + * [item 1, item 2, item 3] + * + * Tokens: + * + * STREAM-START(utf-8) + * FLOW-SEQUENCE-START + * SCALAR("item 1",plain) + * FLOW-ENTRY + * SCALAR("item 2",plain) + * FLOW-ENTRY + * SCALAR("item 3",plain) + * FLOW-SEQUENCE-END + * STREAM-END + * + * 2. A flow mapping: + * + * { + * a simple key: a value, # Note that the KEY token is produced. + * ? a complex key: another value, + * } + * + * Tokens: + * + * STREAM-START(utf-8) + * FLOW-MAPPING-START + * KEY + * SCALAR("a simple key",plain) + * VALUE + * SCALAR("a value",plain) + * FLOW-ENTRY + * KEY + * SCALAR("a complex key",plain) + * VALUE + * SCALAR("another value",plain) + * FLOW-ENTRY + * FLOW-MAPPING-END + * STREAM-END + * + * A simple key is a key which is not denoted by the '?' indicator. Note that + * the Scanner still produce the KEY token whenever it encounters a simple key. + * + * For scanning block collections, the following tokens are used (note that we + * repeat KEY and VALUE here): + * + * BLOCK-SEQUENCE-START + * BLOCK-MAPPING-START + * BLOCK-END + * BLOCK-ENTRY + * KEY + * VALUE + * + * The tokens BLOCK-SEQUENCE-START and BLOCK-MAPPING-START denote indentation + * increase that precedes a block collection (cf. the INDENT token in Python). + * The token BLOCK-END denote indentation decrease that ends a block collection + * (cf. the DEDENT token in Python). However YAML has some syntax pecularities + * that makes detections of these tokens more complex. + * + * The tokens BLOCK-ENTRY, KEY, and VALUE are used to represent the indicators + * '-', '?', and ':' correspondingly. + * + * The following examples show how the tokens BLOCK-SEQUENCE-START, + * BLOCK-MAPPING-START, and BLOCK-END are emitted by the Scanner: + * + * 1. Block sequences: + * + * - item 1 + * - item 2 + * - + * - item 3.1 + * - item 3.2 + * - + * key 1: value 1 + * key 2: value 2 + * + * Tokens: + * + * STREAM-START(utf-8) + * BLOCK-SEQUENCE-START + * BLOCK-ENTRY + * SCALAR("item 1",plain) + * BLOCK-ENTRY + * SCALAR("item 2",plain) + * BLOCK-ENTRY + * BLOCK-SEQUENCE-START + * BLOCK-ENTRY + * SCALAR("item 3.1",plain) + * BLOCK-ENTRY + * SCALAR("item 3.2",plain) + * BLOCK-END + * BLOCK-ENTRY + * BLOCK-MAPPING-START + * KEY + * SCALAR("key 1",plain) + * VALUE + * SCALAR("value 1",plain) + * KEY + * SCALAR("key 2",plain) + * VALUE + * SCALAR("value 2",plain) + * BLOCK-END + * BLOCK-END + * STREAM-END + * + * 2. Block mappings: + * + * a simple key: a value # The KEY token is produced here. + * ? a complex key + * : another value + * a mapping: + * key 1: value 1 + * key 2: value 2 + * a sequence: + * - item 1 + * - item 2 + * + * Tokens: + * + * STREAM-START(utf-8) + * BLOCK-MAPPING-START + * KEY + * SCALAR("a simple key",plain) + * VALUE + * SCALAR("a value",plain) + * KEY + * SCALAR("a complex key",plain) + * VALUE + * SCALAR("another value",plain) + * KEY + * SCALAR("a mapping",plain) + * BLOCK-MAPPING-START + * KEY + * SCALAR("key 1",plain) + * VALUE + * SCALAR("value 1",plain) + * KEY + * SCALAR("key 2",plain) + * VALUE + * SCALAR("value 2",plain) + * BLOCK-END + * KEY + * SCALAR("a sequence",plain) + * VALUE + * BLOCK-SEQUENCE-START + * BLOCK-ENTRY + * SCALAR("item 1",plain) + * BLOCK-ENTRY + * SCALAR("item 2",plain) + * BLOCK-END + * BLOCK-END + * STREAM-END + * + * YAML does not always require to start a new block collection from a new + * line. If the current line contains only '-', '?', and ':' indicators, a new + * block collection may start at the current line. The following examples + * illustrate this case: + * + * 1. Collections in a sequence: + * + * - - item 1 + * - item 2 + * - key 1: value 1 + * key 2: value 2 + * - ? complex key + * : complex value + * + * Tokens: + * + * STREAM-START(utf-8) + * BLOCK-SEQUENCE-START + * BLOCK-ENTRY + * BLOCK-SEQUENCE-START + * BLOCK-ENTRY + * SCALAR("item 1",plain) + * BLOCK-ENTRY + * SCALAR("item 2",plain) + * BLOCK-END + * BLOCK-ENTRY + * BLOCK-MAPPING-START + * KEY + * SCALAR("key 1",plain) + * VALUE + * SCALAR("value 1",plain) + * KEY + * SCALAR("key 2",plain) + * VALUE + * SCALAR("value 2",plain) + * BLOCK-END + * BLOCK-ENTRY + * BLOCK-MAPPING-START + * KEY + * SCALAR("complex key") + * VALUE + * SCALAR("complex value") + * BLOCK-END + * BLOCK-END + * STREAM-END + * + * 2. Collections in a mapping: + * + * ? a sequence + * : - item 1 + * - item 2 + * ? a mapping + * : key 1: value 1 + * key 2: value 2 + * + * Tokens: + * + * STREAM-START(utf-8) + * BLOCK-MAPPING-START + * KEY + * SCALAR("a sequence",plain) + * VALUE + * BLOCK-SEQUENCE-START + * BLOCK-ENTRY + * SCALAR("item 1",plain) + * BLOCK-ENTRY + * SCALAR("item 2",plain) + * BLOCK-END + * KEY + * SCALAR("a mapping",plain) + * VALUE + * BLOCK-MAPPING-START + * KEY + * SCALAR("key 1",plain) + * VALUE + * SCALAR("value 1",plain) + * KEY + * SCALAR("key 2",plain) + * VALUE + * SCALAR("value 2",plain) + * BLOCK-END + * BLOCK-END + * STREAM-END + * + * YAML also permits non-indented sequences if they are included into a block + * mapping. In this case, the token BLOCK-SEQUENCE-START is not produced: + * + * key: + * - item 1 # BLOCK-SEQUENCE-START is NOT produced here. + * - item 2 + * + * Tokens: + * + * STREAM-START(utf-8) + * BLOCK-MAPPING-START + * KEY + * SCALAR("key",plain) + * VALUE + * BLOCK-ENTRY + * SCALAR("item 1",plain) + * BLOCK-ENTRY + * SCALAR("item 2",plain) + * BLOCK-END + */ + +#include "yaml_private.h" + +/* + * Ensure that the buffer contains the required number of characters. + * Return 1 on success, 0 on failure (reader error or memory error). + */ + +#define CACHE(parser,length) \ + (parser->unread >= (length) \ + ? 1 \ + : yaml_parser_update_buffer(parser, (length))) + +/* + * Advance the buffer pointer. + */ + +#define SKIP(parser) \ + (parser->mark.index ++, \ + parser->mark.column ++, \ + parser->unread --, \ + parser->buffer.pointer += WIDTH(parser->buffer)) + +#define SKIP_LINE(parser) \ + (IS_CRLF(parser->buffer) ? \ + (parser->mark.index += 2, \ + parser->mark.column = 0, \ + parser->mark.line ++, \ + parser->unread -= 2, \ + parser->buffer.pointer += 2) : \ + IS_BREAK(parser->buffer) ? \ + (parser->mark.index ++, \ + parser->mark.column = 0, \ + parser->mark.line ++, \ + parser->unread --, \ + parser->buffer.pointer += WIDTH(parser->buffer)) : 0) + +/* + * Copy a character to a string buffer and advance pointers. + */ + +#define READ(parser,string) \ + (STRING_EXTEND(parser,string) ? \ + (COPY(string,parser->buffer), \ + parser->mark.index ++, \ + parser->mark.column ++, \ + parser->unread --, \ + 1) : 0) + +/* + * Copy a line break character to a string buffer and advance pointers. + */ + +#define READ_LINE(parser,string) \ + (STRING_EXTEND(parser,string) ? \ + (((CHECK_AT(parser->buffer,'\r',0) \ + && CHECK_AT(parser->buffer,'\n',1)) ? /* CR LF -> LF */ \ + (*((string).pointer++) = (yaml_char_t) '\n', \ + parser->buffer.pointer += 2, \ + parser->mark.index += 2, \ + parser->mark.column = 0, \ + parser->mark.line ++, \ + parser->unread -= 2) : \ + (CHECK_AT(parser->buffer,'\r',0) \ + || CHECK_AT(parser->buffer,'\n',0)) ? /* CR|LF -> LF */ \ + (*((string).pointer++) = (yaml_char_t) '\n', \ + parser->buffer.pointer ++, \ + parser->mark.index ++, \ + parser->mark.column = 0, \ + parser->mark.line ++, \ + parser->unread --) : \ + (CHECK_AT(parser->buffer,'\xC2',0) \ + && CHECK_AT(parser->buffer,'\x85',1)) ? /* NEL -> LF */ \ + (*((string).pointer++) = (yaml_char_t) '\n', \ + parser->buffer.pointer += 2, \ + parser->mark.index ++, \ + parser->mark.column = 0, \ + parser->mark.line ++, \ + parser->unread --) : \ + (CHECK_AT(parser->buffer,'\xE2',0) && \ + CHECK_AT(parser->buffer,'\x80',1) && \ + (CHECK_AT(parser->buffer,'\xA8',2) || \ + CHECK_AT(parser->buffer,'\xA9',2))) ? /* LS|PS -> LS|PS */ \ + (*((string).pointer++) = *(parser->buffer.pointer++), \ + *((string).pointer++) = *(parser->buffer.pointer++), \ + *((string).pointer++) = *(parser->buffer.pointer++), \ + parser->mark.index ++, \ + parser->mark.column = 0, \ + parser->mark.line ++, \ + parser->unread --) : 0), \ + 1) : 0) + +/* + * Public API declarations. + */ + +YAML_DECLARE(int) +yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token); + +/* + * Error handling. + */ + +static int +yaml_parser_set_scanner_error(yaml_parser_t *parser, const char *context, + yaml_mark_t context_mark, const char *problem); + +/* + * High-level token API. + */ + +YAML_DECLARE(int) +yaml_parser_fetch_more_tokens(yaml_parser_t *parser); + +static int +yaml_parser_fetch_next_token(yaml_parser_t *parser); + +/* + * Potential simple keys. + */ + +static int +yaml_parser_stale_simple_keys(yaml_parser_t *parser); + +static int +yaml_parser_save_simple_key(yaml_parser_t *parser); + +static int +yaml_parser_remove_simple_key(yaml_parser_t *parser); + +static int +yaml_parser_increase_flow_level(yaml_parser_t *parser); + +static int +yaml_parser_decrease_flow_level(yaml_parser_t *parser); + +/* + * Indentation treatment. + */ + +static int +yaml_parser_roll_indent(yaml_parser_t *parser, ptrdiff_t column, + ptrdiff_t number, yaml_token_type_t type, yaml_mark_t mark); + +static int +yaml_parser_unroll_indent(yaml_parser_t *parser, ptrdiff_t column); + +/* + * Token fetchers. + */ + +static int +yaml_parser_fetch_stream_start(yaml_parser_t *parser); + +static int +yaml_parser_fetch_stream_end(yaml_parser_t *parser); + +static int +yaml_parser_fetch_directive(yaml_parser_t *parser); + +static int +yaml_parser_fetch_document_indicator(yaml_parser_t *parser, + yaml_token_type_t type); + +static int +yaml_parser_fetch_flow_collection_start(yaml_parser_t *parser, + yaml_token_type_t type); + +static int +yaml_parser_fetch_flow_collection_end(yaml_parser_t *parser, + yaml_token_type_t type); + +static int +yaml_parser_fetch_flow_entry(yaml_parser_t *parser); + +static int +yaml_parser_fetch_block_entry(yaml_parser_t *parser); + +static int +yaml_parser_fetch_key(yaml_parser_t *parser); + +static int +yaml_parser_fetch_value(yaml_parser_t *parser); + +static int +yaml_parser_fetch_anchor(yaml_parser_t *parser, yaml_token_type_t type); + +static int +yaml_parser_fetch_tag(yaml_parser_t *parser); + +static int +yaml_parser_fetch_block_scalar(yaml_parser_t *parser, int literal); + +static int +yaml_parser_fetch_flow_scalar(yaml_parser_t *parser, int single); + +static int +yaml_parser_fetch_plain_scalar(yaml_parser_t *parser); + +/* + * Token scanners. + */ + +static int +yaml_parser_scan_to_next_token(yaml_parser_t *parser); + +static int +yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token); + +static int +yaml_parser_scan_directive_name(yaml_parser_t *parser, + yaml_mark_t start_mark, yaml_char_t **name); + +static int +yaml_parser_scan_version_directive_value(yaml_parser_t *parser, + yaml_mark_t start_mark, int *major, int *minor); + +static int +yaml_parser_scan_version_directive_number(yaml_parser_t *parser, + yaml_mark_t start_mark, int *number); + +static int +yaml_parser_scan_tag_directive_value(yaml_parser_t *parser, + yaml_mark_t mark, yaml_char_t **handle, yaml_char_t **prefix); + +static int +yaml_parser_scan_anchor(yaml_parser_t *parser, yaml_token_t *token, + yaml_token_type_t type); + +static int +yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token); + +static int +yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive, + yaml_mark_t start_mark, yaml_char_t **handle); + +static int +yaml_parser_scan_tag_uri(yaml_parser_t *parser, int directive, + yaml_char_t *head, yaml_mark_t start_mark, yaml_char_t **uri); + +static int +yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive, + yaml_mark_t start_mark, yaml_string_t *string); + +static int +yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token, + int literal); + +static int +yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser, + int *indent, yaml_string_t *breaks, + yaml_mark_t start_mark, yaml_mark_t *end_mark); + +static int +yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token, + int single); + +static int +yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token); + +/* + * Get the next token. + */ + +YAML_DECLARE(int) +yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token) +{ + assert(parser); /* Non-NULL parser object is expected. */ + assert(token); /* Non-NULL token object is expected. */ + + /* Erase the token object. */ + + memset(token, 0, sizeof(yaml_token_t)); + + /* No tokens after STREAM-END or error. */ + + if (parser->stream_end_produced || parser->error) { + return 1; + } + + /* Ensure that the tokens queue contains enough tokens. */ + + if (!parser->token_available) { + if (!yaml_parser_fetch_more_tokens(parser)) + return 0; + } + + /* Fetch the next token from the queue. */ + + *token = DEQUEUE(parser, parser->tokens); + parser->token_available = 0; + parser->tokens_parsed ++; + + if (token->type == YAML_STREAM_END_TOKEN) { + parser->stream_end_produced = 1; + } + + return 1; +} + +/* + * Set the scanner error and return 0. + */ + +static int +yaml_parser_set_scanner_error(yaml_parser_t *parser, const char *context, + yaml_mark_t context_mark, const char *problem) +{ + parser->error = YAML_SCANNER_ERROR; + parser->context = context; + parser->context_mark = context_mark; + parser->problem = problem; + parser->problem_mark = parser->mark; + + return 0; +} + +/* + * Ensure that the tokens queue contains at least one token which can be + * returned to the Parser. + */ + +YAML_DECLARE(int) +yaml_parser_fetch_more_tokens(yaml_parser_t *parser) +{ + int need_more_tokens; + + /* While we need more tokens to fetch, do it. */ + + while (1) + { + /* + * Check if we really need to fetch more tokens. + */ + + need_more_tokens = 0; + + if (parser->tokens.head == parser->tokens.tail) + { + /* Queue is empty. */ + + need_more_tokens = 1; + } + else + { + yaml_simple_key_t *simple_key; + + /* Check if any potential simple key may occupy the head position. */ + + if (!yaml_parser_stale_simple_keys(parser)) + return 0; + + for (simple_key = parser->simple_keys.start; + simple_key != parser->simple_keys.top; simple_key++) { + if (simple_key->possible + && simple_key->token_number == parser->tokens_parsed) { + need_more_tokens = 1; + break; + } + } + } + + /* We are finished. */ + + if (!need_more_tokens) + break; + + /* Fetch the next token. */ + + if (!yaml_parser_fetch_next_token(parser)) + return 0; + } + + parser->token_available = 1; + + return 1; +} + +/* + * The dispatcher for token fetchers. + */ + +static int +yaml_parser_fetch_next_token(yaml_parser_t *parser) +{ + /* Ensure that the buffer is initialized. */ + + if (!CACHE(parser, 1)) + return 0; + + /* Check if we just started scanning. Fetch STREAM-START then. */ + + if (!parser->stream_start_produced) + return yaml_parser_fetch_stream_start(parser); + + /* Eat whitespaces and comments until we reach the next token. */ + + if (!yaml_parser_scan_to_next_token(parser)) + return 0; + + /* Remove obsolete potential simple keys. */ + + if (!yaml_parser_stale_simple_keys(parser)) + return 0; + + /* Check the indentation level against the current column. */ + + if (!yaml_parser_unroll_indent(parser, parser->mark.column)) + return 0; + + /* + * Ensure that the buffer contains at least 4 characters. 4 is the length + * of the longest indicators ('--- ' and '... '). + */ + + if (!CACHE(parser, 4)) + return 0; + + /* Is it the end of the stream? */ + + if (IS_Z(parser->buffer)) + return yaml_parser_fetch_stream_end(parser); + + /* Is it a directive? */ + + if (parser->mark.column == 0 && CHECK(parser->buffer, '%')) + return yaml_parser_fetch_directive(parser); + + /* Is it the document start indicator? */ + + if (parser->mark.column == 0 + && CHECK_AT(parser->buffer, '-', 0) + && CHECK_AT(parser->buffer, '-', 1) + && CHECK_AT(parser->buffer, '-', 2) + && IS_BLANKZ_AT(parser->buffer, 3)) + return yaml_parser_fetch_document_indicator(parser, + YAML_DOCUMENT_START_TOKEN); + + /* Is it the document end indicator? */ + + if (parser->mark.column == 0 + && CHECK_AT(parser->buffer, '.', 0) + && CHECK_AT(parser->buffer, '.', 1) + && CHECK_AT(parser->buffer, '.', 2) + && IS_BLANKZ_AT(parser->buffer, 3)) + return yaml_parser_fetch_document_indicator(parser, + YAML_DOCUMENT_END_TOKEN); + + /* Is it the flow sequence start indicator? */ + + if (CHECK(parser->buffer, '[')) + return yaml_parser_fetch_flow_collection_start(parser, + YAML_FLOW_SEQUENCE_START_TOKEN); + + /* Is it the flow mapping start indicator? */ + + if (CHECK(parser->buffer, '{')) + return yaml_parser_fetch_flow_collection_start(parser, + YAML_FLOW_MAPPING_START_TOKEN); + + /* Is it the flow sequence end indicator? */ + + if (CHECK(parser->buffer, ']')) + return yaml_parser_fetch_flow_collection_end(parser, + YAML_FLOW_SEQUENCE_END_TOKEN); + + /* Is it the flow mapping end indicator? */ + + if (CHECK(parser->buffer, '}')) + return yaml_parser_fetch_flow_collection_end(parser, + YAML_FLOW_MAPPING_END_TOKEN); + + /* Is it the flow entry indicator? */ + + if (CHECK(parser->buffer, ',')) + return yaml_parser_fetch_flow_entry(parser); + + /* Is it the block entry indicator? */ + + if (CHECK(parser->buffer, '-') && IS_BLANKZ_AT(parser->buffer, 1)) + return yaml_parser_fetch_block_entry(parser); + + /* Is it the key indicator? */ + + if (CHECK(parser->buffer, '?') + && (parser->flow_level || IS_BLANKZ_AT(parser->buffer, 1))) + return yaml_parser_fetch_key(parser); + + /* Is it the value indicator? */ + + if (CHECK(parser->buffer, ':') + && (parser->flow_level || IS_BLANKZ_AT(parser->buffer, 1))) + return yaml_parser_fetch_value(parser); + + /* Is it an alias? */ + + if (CHECK(parser->buffer, '*')) + return yaml_parser_fetch_anchor(parser, YAML_ALIAS_TOKEN); + + /* Is it an anchor? */ + + if (CHECK(parser->buffer, '&')) + return yaml_parser_fetch_anchor(parser, YAML_ANCHOR_TOKEN); + + /* Is it a tag? */ + + if (CHECK(parser->buffer, '!')) + return yaml_parser_fetch_tag(parser); + + /* Is it a literal scalar? */ + + if (CHECK(parser->buffer, '|') && !parser->flow_level) + return yaml_parser_fetch_block_scalar(parser, 1); + + /* Is it a folded scalar? */ + + if (CHECK(parser->buffer, '>') && !parser->flow_level) + return yaml_parser_fetch_block_scalar(parser, 0); + + /* Is it a single-quoted scalar? */ + + if (CHECK(parser->buffer, '\'')) + return yaml_parser_fetch_flow_scalar(parser, 1); + + /* Is it a double-quoted scalar? */ + + if (CHECK(parser->buffer, '"')) + return yaml_parser_fetch_flow_scalar(parser, 0); + + /* + * Is it a plain scalar? + * + * A plain scalar may start with any non-blank characters except + * + * '-', '?', ':', ',', '[', ']', '{', '}', + * '#', '&', '*', '!', '|', '>', '\'', '\"', + * '%', '@', '`'. + * + * In the block context (and, for the '-' indicator, in the flow context + * too), it may also start with the characters + * + * '-', '?', ':' + * + * if it is followed by a non-space character. + * + * The last rule is more restrictive than the specification requires. + */ + + if (!(IS_BLANKZ(parser->buffer) || CHECK(parser->buffer, '-') + || CHECK(parser->buffer, '?') || CHECK(parser->buffer, ':') + || CHECK(parser->buffer, ',') || CHECK(parser->buffer, '[') + || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '{') + || CHECK(parser->buffer, '}') || CHECK(parser->buffer, '#') + || CHECK(parser->buffer, '&') || CHECK(parser->buffer, '*') + || CHECK(parser->buffer, '!') || CHECK(parser->buffer, '|') + || CHECK(parser->buffer, '>') || CHECK(parser->buffer, '\'') + || CHECK(parser->buffer, '"') || CHECK(parser->buffer, '%') + || CHECK(parser->buffer, '@') || CHECK(parser->buffer, '`')) || + (CHECK(parser->buffer, '-') && !IS_BLANK_AT(parser->buffer, 1)) || + (!parser->flow_level && + (CHECK(parser->buffer, '?') || CHECK(parser->buffer, ':')) + && !IS_BLANKZ_AT(parser->buffer, 1))) + return yaml_parser_fetch_plain_scalar(parser); + + /* + * If we don't determine the token type so far, it is an error. + */ + + return yaml_parser_set_scanner_error(parser, + "while scanning for the next token", parser->mark, + "found character that cannot start any token"); +} + +/* + * Check the list of potential simple keys and remove the positions that + * cannot contain simple keys anymore. + */ + +static int +yaml_parser_stale_simple_keys(yaml_parser_t *parser) +{ + yaml_simple_key_t *simple_key; + + /* Check for a potential simple key for each flow level. */ + + for (simple_key = parser->simple_keys.start; + simple_key != parser->simple_keys.top; simple_key ++) + { + /* + * The specification requires that a simple key + * + * - is limited to a single line, + * - is shorter than 1024 characters. + */ + + if (simple_key->possible + && (simple_key->mark.line < parser->mark.line + || simple_key->mark.index+1024 < parser->mark.index)) { + + /* Check if the potential simple key to be removed is required. */ + + if (simple_key->required) { + return yaml_parser_set_scanner_error(parser, + "while scanning a simple key", simple_key->mark, + "could not find expected ':'"); + } + + simple_key->possible = 0; + } + } + + return 1; +} + +/* + * Check if a simple key may start at the current position and add it if + * needed. + */ + +static int +yaml_parser_save_simple_key(yaml_parser_t *parser) +{ + /* + * A simple key is required at the current position if the scanner is in + * the block context and the current column coincides with the indentation + * level. + */ + + int required = (!parser->flow_level + && parser->indent == (ptrdiff_t)parser->mark.column); + + /* + * If the current position may start a simple key, save it. + */ + + if (parser->simple_key_allowed) + { + yaml_simple_key_t simple_key; + simple_key.possible = 1; + simple_key.required = required; + simple_key.token_number = + parser->tokens_parsed + (parser->tokens.tail - parser->tokens.head); + simple_key.mark = parser->mark; + + if (!yaml_parser_remove_simple_key(parser)) return 0; + + *(parser->simple_keys.top-1) = simple_key; + } + + return 1; +} + +/* + * Remove a potential simple key at the current flow level. + */ + +static int +yaml_parser_remove_simple_key(yaml_parser_t *parser) +{ + yaml_simple_key_t *simple_key = parser->simple_keys.top-1; + + if (simple_key->possible) + { + /* If the key is required, it is an error. */ + + if (simple_key->required) { + return yaml_parser_set_scanner_error(parser, + "while scanning a simple key", simple_key->mark, + "could not find expected ':'"); + } + } + + /* Remove the key from the stack. */ + + simple_key->possible = 0; + + return 1; +} + +/* + * Increase the flow level and resize the simple key list if needed. + */ + +static int +yaml_parser_increase_flow_level(yaml_parser_t *parser) +{ + yaml_simple_key_t empty_simple_key = { 0, 0, 0, { 0, 0, 0 } }; + + /* Reset the simple key on the next level. */ + + if (!PUSH(parser, parser->simple_keys, empty_simple_key)) + return 0; + + /* Increase the flow level. */ + + if (parser->flow_level == INT_MAX) { + parser->error = YAML_MEMORY_ERROR; + return 0; + } + + parser->flow_level++; + + return 1; +} + +/* + * Decrease the flow level. + */ + +static int +yaml_parser_decrease_flow_level(yaml_parser_t *parser) +{ + yaml_simple_key_t dummy_key; /* Used to eliminate a compiler warning. */ + + if (parser->flow_level) { + parser->flow_level --; + dummy_key = POP(parser, parser->simple_keys); + } + + return 1; +} + +/* + * Push the current indentation level to the stack and set the new level + * the current column is greater than the indentation level. In this case, + * append or insert the specified token into the token queue. + * + */ + +static int +yaml_parser_roll_indent(yaml_parser_t *parser, ptrdiff_t column, + ptrdiff_t number, yaml_token_type_t type, yaml_mark_t mark) +{ + yaml_token_t token; + + /* In the flow context, do nothing. */ + + if (parser->flow_level) + return 1; + + if (parser->indent < column) + { + /* + * Push the current indentation level to the stack and set the new + * indentation level. + */ + + if (!PUSH(parser, parser->indents, parser->indent)) + return 0; + + if (column > INT_MAX) { + parser->error = YAML_MEMORY_ERROR; + return 0; + } + + parser->indent = column; + + /* Create a token and insert it into the queue. */ + + TOKEN_INIT(token, type, mark, mark); + + if (number == -1) { + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + } + else { + if (!QUEUE_INSERT(parser, + parser->tokens, number - parser->tokens_parsed, token)) + return 0; + } + } + + return 1; +} + +/* + * Pop indentation levels from the indents stack until the current level + * becomes less or equal to the column. For each intendation level, append + * the BLOCK-END token. + */ + + +static int +yaml_parser_unroll_indent(yaml_parser_t *parser, ptrdiff_t column) +{ + yaml_token_t token; + + /* In the flow context, do nothing. */ + + if (parser->flow_level) + return 1; + + /* Loop through the intendation levels in the stack. */ + + while (parser->indent > column) + { + /* Create a token and append it to the queue. */ + + TOKEN_INIT(token, YAML_BLOCK_END_TOKEN, parser->mark, parser->mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + /* Pop the indentation level. */ + + parser->indent = POP(parser, parser->indents); + } + + return 1; +} + +/* + * Initialize the scanner and produce the STREAM-START token. + */ + +static int +yaml_parser_fetch_stream_start(yaml_parser_t *parser) +{ + yaml_simple_key_t simple_key = { 0, 0, 0, { 0, 0, 0 } }; + yaml_token_t token; + + /* Set the initial indentation. */ + + parser->indent = -1; + + /* Initialize the simple key stack. */ + + if (!PUSH(parser, parser->simple_keys, simple_key)) + return 0; + + /* A simple key is allowed at the beginning of the stream. */ + + parser->simple_key_allowed = 1; + + /* We have started. */ + + parser->stream_start_produced = 1; + + /* Create the STREAM-START token and append it to the queue. */ + + STREAM_START_TOKEN_INIT(token, parser->encoding, + parser->mark, parser->mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the STREAM-END token and shut down the scanner. + */ + +static int +yaml_parser_fetch_stream_end(yaml_parser_t *parser) +{ + yaml_token_t token; + + /* Force new line. */ + + if (parser->mark.column != 0) { + parser->mark.column = 0; + parser->mark.line ++; + } + + /* Reset the indentation level. */ + + if (!yaml_parser_unroll_indent(parser, -1)) + return 0; + + /* Reset simple keys. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + parser->simple_key_allowed = 0; + + /* Create the STREAM-END token and append it to the queue. */ + + STREAM_END_TOKEN_INIT(token, parser->mark, parser->mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce a VERSION-DIRECTIVE or TAG-DIRECTIVE token. + */ + +static int +yaml_parser_fetch_directive(yaml_parser_t *parser) +{ + yaml_token_t token; + + /* Reset the indentation level. */ + + if (!yaml_parser_unroll_indent(parser, -1)) + return 0; + + /* Reset simple keys. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + parser->simple_key_allowed = 0; + + /* Create the YAML-DIRECTIVE or TAG-DIRECTIVE token. */ + + if (!yaml_parser_scan_directive(parser, &token)) + return 0; + + /* Append the token to the queue. */ + + if (!ENQUEUE(parser, parser->tokens, token)) { + yaml_token_delete(&token); + return 0; + } + + return 1; +} + +/* + * Produce the DOCUMENT-START or DOCUMENT-END token. + */ + +static int +yaml_parser_fetch_document_indicator(yaml_parser_t *parser, + yaml_token_type_t type) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + + /* Reset the indentation level. */ + + if (!yaml_parser_unroll_indent(parser, -1)) + return 0; + + /* Reset simple keys. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + parser->simple_key_allowed = 0; + + /* Consume the token. */ + + start_mark = parser->mark; + + SKIP(parser); + SKIP(parser); + SKIP(parser); + + end_mark = parser->mark; + + /* Create the DOCUMENT-START or DOCUMENT-END token. */ + + TOKEN_INIT(token, type, start_mark, end_mark); + + /* Append the token to the queue. */ + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the FLOW-SEQUENCE-START or FLOW-MAPPING-START token. + */ + +static int +yaml_parser_fetch_flow_collection_start(yaml_parser_t *parser, + yaml_token_type_t type) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + + /* The indicators '[' and '{' may start a simple key. */ + + if (!yaml_parser_save_simple_key(parser)) + return 0; + + /* Increase the flow level. */ + + if (!yaml_parser_increase_flow_level(parser)) + return 0; + + /* A simple key may follow the indicators '[' and '{'. */ + + parser->simple_key_allowed = 1; + + /* Consume the token. */ + + start_mark = parser->mark; + SKIP(parser); + end_mark = parser->mark; + + /* Create the FLOW-SEQUENCE-START of FLOW-MAPPING-START token. */ + + TOKEN_INIT(token, type, start_mark, end_mark); + + /* Append the token to the queue. */ + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the FLOW-SEQUENCE-END or FLOW-MAPPING-END token. + */ + +static int +yaml_parser_fetch_flow_collection_end(yaml_parser_t *parser, + yaml_token_type_t type) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + + /* Reset any potential simple key on the current flow level. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + /* Decrease the flow level. */ + + if (!yaml_parser_decrease_flow_level(parser)) + return 0; + + /* No simple keys after the indicators ']' and '}'. */ + + parser->simple_key_allowed = 0; + + /* Consume the token. */ + + start_mark = parser->mark; + SKIP(parser); + end_mark = parser->mark; + + /* Create the FLOW-SEQUENCE-END of FLOW-MAPPING-END token. */ + + TOKEN_INIT(token, type, start_mark, end_mark); + + /* Append the token to the queue. */ + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the FLOW-ENTRY token. + */ + +static int +yaml_parser_fetch_flow_entry(yaml_parser_t *parser) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + + /* Reset any potential simple keys on the current flow level. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + /* Simple keys are allowed after ','. */ + + parser->simple_key_allowed = 1; + + /* Consume the token. */ + + start_mark = parser->mark; + SKIP(parser); + end_mark = parser->mark; + + /* Create the FLOW-ENTRY token and append it to the queue. */ + + TOKEN_INIT(token, YAML_FLOW_ENTRY_TOKEN, start_mark, end_mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the BLOCK-ENTRY token. + */ + +static int +yaml_parser_fetch_block_entry(yaml_parser_t *parser) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + + /* Check if the scanner is in the block context. */ + + if (!parser->flow_level) + { + /* Check if we are allowed to start a new entry. */ + + if (!parser->simple_key_allowed) { + return yaml_parser_set_scanner_error(parser, NULL, parser->mark, + "block sequence entries are not allowed in this context"); + } + + /* Add the BLOCK-SEQUENCE-START token if needed. */ + + if (!yaml_parser_roll_indent(parser, parser->mark.column, -1, + YAML_BLOCK_SEQUENCE_START_TOKEN, parser->mark)) + return 0; + } + else + { + /* + * It is an error for the '-' indicator to occur in the flow context, + * but we let the Parser detect and report about it because the Parser + * is able to point to the context. + */ + } + + /* Reset any potential simple keys on the current flow level. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + /* Simple keys are allowed after '-'. */ + + parser->simple_key_allowed = 1; + + /* Consume the token. */ + + start_mark = parser->mark; + SKIP(parser); + end_mark = parser->mark; + + /* Create the BLOCK-ENTRY token and append it to the queue. */ + + TOKEN_INIT(token, YAML_BLOCK_ENTRY_TOKEN, start_mark, end_mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the KEY token. + */ + +static int +yaml_parser_fetch_key(yaml_parser_t *parser) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + + /* In the block context, additional checks are required. */ + + if (!parser->flow_level) + { + /* Check if we are allowed to start a new key (not nessesary simple). */ + + if (!parser->simple_key_allowed) { + return yaml_parser_set_scanner_error(parser, NULL, parser->mark, + "mapping keys are not allowed in this context"); + } + + /* Add the BLOCK-MAPPING-START token if needed. */ + + if (!yaml_parser_roll_indent(parser, parser->mark.column, -1, + YAML_BLOCK_MAPPING_START_TOKEN, parser->mark)) + return 0; + } + + /* Reset any potential simple keys on the current flow level. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + /* Simple keys are allowed after '?' in the block context. */ + + parser->simple_key_allowed = (!parser->flow_level); + + /* Consume the token. */ + + start_mark = parser->mark; + SKIP(parser); + end_mark = parser->mark; + + /* Create the KEY token and append it to the queue. */ + + TOKEN_INIT(token, YAML_KEY_TOKEN, start_mark, end_mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the VALUE token. + */ + +static int +yaml_parser_fetch_value(yaml_parser_t *parser) +{ + yaml_mark_t start_mark, end_mark; + yaml_token_t token; + yaml_simple_key_t *simple_key = parser->simple_keys.top-1; + + /* Have we found a simple key? */ + + if (simple_key->possible) + { + + /* Create the KEY token and insert it into the queue. */ + + TOKEN_INIT(token, YAML_KEY_TOKEN, simple_key->mark, simple_key->mark); + + if (!QUEUE_INSERT(parser, parser->tokens, + simple_key->token_number - parser->tokens_parsed, token)) + return 0; + + /* In the block context, we may need to add the BLOCK-MAPPING-START token. */ + + if (!yaml_parser_roll_indent(parser, simple_key->mark.column, + simple_key->token_number, + YAML_BLOCK_MAPPING_START_TOKEN, simple_key->mark)) + return 0; + + /* Remove the simple key. */ + + simple_key->possible = 0; + + /* A simple key cannot follow another simple key. */ + + parser->simple_key_allowed = 0; + } + else + { + /* The ':' indicator follows a complex key. */ + + /* In the block context, extra checks are required. */ + + if (!parser->flow_level) + { + /* Check if we are allowed to start a complex value. */ + + if (!parser->simple_key_allowed) { + return yaml_parser_set_scanner_error(parser, NULL, parser->mark, + "mapping values are not allowed in this context"); + } + + /* Add the BLOCK-MAPPING-START token if needed. */ + + if (!yaml_parser_roll_indent(parser, parser->mark.column, -1, + YAML_BLOCK_MAPPING_START_TOKEN, parser->mark)) + return 0; + } + + /* Simple keys after ':' are allowed in the block context. */ + + parser->simple_key_allowed = (!parser->flow_level); + } + + /* Consume the token. */ + + start_mark = parser->mark; + SKIP(parser); + end_mark = parser->mark; + + /* Create the VALUE token and append it to the queue. */ + + TOKEN_INIT(token, YAML_VALUE_TOKEN, start_mark, end_mark); + + if (!ENQUEUE(parser, parser->tokens, token)) + return 0; + + return 1; +} + +/* + * Produce the ALIAS or ANCHOR token. + */ + +static int +yaml_parser_fetch_anchor(yaml_parser_t *parser, yaml_token_type_t type) +{ + yaml_token_t token; + + /* An anchor or an alias could be a simple key. */ + + if (!yaml_parser_save_simple_key(parser)) + return 0; + + /* A simple key cannot follow an anchor or an alias. */ + + parser->simple_key_allowed = 0; + + /* Create the ALIAS or ANCHOR token and append it to the queue. */ + + if (!yaml_parser_scan_anchor(parser, &token, type)) + return 0; + + if (!ENQUEUE(parser, parser->tokens, token)) { + yaml_token_delete(&token); + return 0; + } + return 1; +} + +/* + * Produce the TAG token. + */ + +static int +yaml_parser_fetch_tag(yaml_parser_t *parser) +{ + yaml_token_t token; + + /* A tag could be a simple key. */ + + if (!yaml_parser_save_simple_key(parser)) + return 0; + + /* A simple key cannot follow a tag. */ + + parser->simple_key_allowed = 0; + + /* Create the TAG token and append it to the queue. */ + + if (!yaml_parser_scan_tag(parser, &token)) + return 0; + + if (!ENQUEUE(parser, parser->tokens, token)) { + yaml_token_delete(&token); + return 0; + } + + return 1; +} + +/* + * Produce the SCALAR(...,literal) or SCALAR(...,folded) tokens. + */ + +static int +yaml_parser_fetch_block_scalar(yaml_parser_t *parser, int literal) +{ + yaml_token_t token; + + /* Remove any potential simple keys. */ + + if (!yaml_parser_remove_simple_key(parser)) + return 0; + + /* A simple key may follow a block scalar. */ + + parser->simple_key_allowed = 1; + + /* Create the SCALAR token and append it to the queue. */ + + if (!yaml_parser_scan_block_scalar(parser, &token, literal)) + return 0; + + if (!ENQUEUE(parser, parser->tokens, token)) { + yaml_token_delete(&token); + return 0; + } + + return 1; +} + +/* + * Produce the SCALAR(...,single-quoted) or SCALAR(...,double-quoted) tokens. + */ + +static int +yaml_parser_fetch_flow_scalar(yaml_parser_t *parser, int single) +{ + yaml_token_t token; + + /* A plain scalar could be a simple key. */ + + if (!yaml_parser_save_simple_key(parser)) + return 0; + + /* A simple key cannot follow a flow scalar. */ + + parser->simple_key_allowed = 0; + + /* Create the SCALAR token and append it to the queue. */ + + if (!yaml_parser_scan_flow_scalar(parser, &token, single)) + return 0; + + if (!ENQUEUE(parser, parser->tokens, token)) { + yaml_token_delete(&token); + return 0; + } + + return 1; +} + +/* + * Produce the SCALAR(...,plain) token. + */ + +static int +yaml_parser_fetch_plain_scalar(yaml_parser_t *parser) +{ + yaml_token_t token; + + /* A plain scalar could be a simple key. */ + + if (!yaml_parser_save_simple_key(parser)) + return 0; + + /* A simple key cannot follow a flow scalar. */ + + parser->simple_key_allowed = 0; + + /* Create the SCALAR token and append it to the queue. */ + + if (!yaml_parser_scan_plain_scalar(parser, &token)) + return 0; + + if (!ENQUEUE(parser, parser->tokens, token)) { + yaml_token_delete(&token); + return 0; + } + + return 1; +} + +/* + * Eat whitespaces and comments until the next token is found. + */ + +static int +yaml_parser_scan_to_next_token(yaml_parser_t *parser) +{ + /* Until the next token is not found. */ + + while (1) + { + /* Allow the BOM mark to start a line. */ + + if (!CACHE(parser, 1)) return 0; + + if (parser->mark.column == 0 && IS_BOM(parser->buffer)) + SKIP(parser); + + /* + * Eat whitespaces. + * + * Tabs are allowed: + * + * - in the flow context; + * - in the block context, but not at the beginning of the line or + * after '-', '?', or ':' (complex value). + */ + + if (!CACHE(parser, 1)) return 0; + + while (CHECK(parser->buffer,' ') || + ((parser->flow_level || !parser->simple_key_allowed) && + CHECK(parser->buffer, '\t'))) { + SKIP(parser); + if (!CACHE(parser, 1)) return 0; + } + + /* Eat a comment until a line break. */ + + if (CHECK(parser->buffer, '#')) { + while (!IS_BREAKZ(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) return 0; + } + } + + /* If it is a line break, eat it. */ + + if (IS_BREAK(parser->buffer)) + { + if (!CACHE(parser, 2)) return 0; + SKIP_LINE(parser); + + /* In the block context, a new line may start a simple key. */ + + if (!parser->flow_level) { + parser->simple_key_allowed = 1; + } + } + else + { + /* We have found a token. */ + + break; + } + } + + return 1; +} + +/* + * Scan a YAML-DIRECTIVE or TAG-DIRECTIVE token. + * + * Scope: + * %YAML 1.1 # a comment \n + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * %TAG !yaml! tag:yaml.org,2002: \n + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + */ + +int +yaml_parser_scan_directive(yaml_parser_t *parser, yaml_token_t *token) +{ + yaml_mark_t start_mark, end_mark; + yaml_char_t *name = NULL; + int major, minor; + yaml_char_t *handle = NULL, *prefix = NULL; + + /* Eat '%'. */ + + start_mark = parser->mark; + + SKIP(parser); + + /* Scan the directive name. */ + + if (!yaml_parser_scan_directive_name(parser, start_mark, &name)) + goto error; + + /* Is it a YAML directive? */ + + if (strcmp((char *)name, "YAML") == 0) + { + /* Scan the VERSION directive value. */ + + if (!yaml_parser_scan_version_directive_value(parser, start_mark, + &major, &minor)) + goto error; + + end_mark = parser->mark; + + /* Create a VERSION-DIRECTIVE token. */ + + VERSION_DIRECTIVE_TOKEN_INIT(*token, major, minor, + start_mark, end_mark); + } + + /* Is it a TAG directive? */ + + else if (strcmp((char *)name, "TAG") == 0) + { + /* Scan the TAG directive value. */ + + if (!yaml_parser_scan_tag_directive_value(parser, start_mark, + &handle, &prefix)) + goto error; + + end_mark = parser->mark; + + /* Create a TAG-DIRECTIVE token. */ + + TAG_DIRECTIVE_TOKEN_INIT(*token, handle, prefix, + start_mark, end_mark); + } + + /* Unknown directive. */ + + else + { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "found uknown directive name"); + goto error; + } + + /* Eat the rest of the line including any comments. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_BLANK(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) goto error; + } + + if (CHECK(parser->buffer, '#')) { + while (!IS_BREAKZ(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) goto error; + } + } + + /* Check if we are at the end of the line. */ + + if (!IS_BREAKZ(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "did not find expected comment or line break"); + goto error; + } + + /* Eat a line break. */ + + if (IS_BREAK(parser->buffer)) { + if (!CACHE(parser, 2)) goto error; + SKIP_LINE(parser); + } + + yaml_free(name); + + return 1; + +error: + yaml_free(prefix); + yaml_free(handle); + yaml_free(name); + return 0; +} + +/* + * Scan the directive name. + * + * Scope: + * %YAML 1.1 # a comment \n + * ^^^^ + * %TAG !yaml! tag:yaml.org,2002: \n + * ^^^ + */ + +static int +yaml_parser_scan_directive_name(yaml_parser_t *parser, + yaml_mark_t start_mark, yaml_char_t **name) +{ + yaml_string_t string = NULL_STRING; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + + /* Consume the directive name. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_ALPHA(parser->buffer)) + { + if (!READ(parser, string)) goto error; + if (!CACHE(parser, 1)) goto error; + } + + /* Check if the name is empty. */ + + if (string.start == string.pointer) { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "could not find expected directive name"); + goto error; + } + + /* Check for an blank character after the name. */ + + if (!IS_BLANKZ(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a directive", + start_mark, "found unexpected non-alphabetical character"); + goto error; + } + + *name = string.start; + + return 1; + +error: + STRING_DEL(parser, string); + return 0; +} + +/* + * Scan the value of VERSION-DIRECTIVE. + * + * Scope: + * %YAML 1.1 # a comment \n + * ^^^^^^ + */ + +static int +yaml_parser_scan_version_directive_value(yaml_parser_t *parser, + yaml_mark_t start_mark, int *major, int *minor) +{ + /* Eat whitespaces. */ + + if (!CACHE(parser, 1)) return 0; + + while (IS_BLANK(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) return 0; + } + + /* Consume the major version number. */ + + if (!yaml_parser_scan_version_directive_number(parser, start_mark, major)) + return 0; + + /* Eat '.'. */ + + if (!CHECK(parser->buffer, '.')) { + return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", + start_mark, "did not find expected digit or '.' character"); + } + + SKIP(parser); + + /* Consume the minor version number. */ + + if (!yaml_parser_scan_version_directive_number(parser, start_mark, minor)) + return 0; + + return 1; +} + +#define MAX_NUMBER_LENGTH 9 + +/* + * Scan the version number of VERSION-DIRECTIVE. + * + * Scope: + * %YAML 1.1 # a comment \n + * ^ + * %YAML 1.1 # a comment \n + * ^ + */ + +static int +yaml_parser_scan_version_directive_number(yaml_parser_t *parser, + yaml_mark_t start_mark, int *number) +{ + int value = 0; + size_t length = 0; + + /* Repeat while the next character is digit. */ + + if (!CACHE(parser, 1)) return 0; + + while (IS_DIGIT(parser->buffer)) + { + /* Check if the number is too long. */ + + if (++length > MAX_NUMBER_LENGTH) { + return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", + start_mark, "found extremely long version number"); + } + + value = value*10 + AS_DIGIT(parser->buffer); + + SKIP(parser); + + if (!CACHE(parser, 1)) return 0; + } + + /* Check if the number was present. */ + + if (!length) { + return yaml_parser_set_scanner_error(parser, "while scanning a %YAML directive", + start_mark, "did not find expected version number"); + } + + *number = value; + + return 1; +} + +/* + * Scan the value of a TAG-DIRECTIVE token. + * + * Scope: + * %TAG !yaml! tag:yaml.org,2002: \n + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + */ + +static int +yaml_parser_scan_tag_directive_value(yaml_parser_t *parser, + yaml_mark_t start_mark, yaml_char_t **handle, yaml_char_t **prefix) +{ + yaml_char_t *handle_value = NULL; + yaml_char_t *prefix_value = NULL; + + /* Eat whitespaces. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_BLANK(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) goto error; + } + + /* Scan a handle. */ + + if (!yaml_parser_scan_tag_handle(parser, 1, start_mark, &handle_value)) + goto error; + + /* Expect a whitespace. */ + + if (!CACHE(parser, 1)) goto error; + + if (!IS_BLANK(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", + start_mark, "did not find expected whitespace"); + goto error; + } + + /* Eat whitespaces. */ + + while (IS_BLANK(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) goto error; + } + + /* Scan a prefix. */ + + if (!yaml_parser_scan_tag_uri(parser, 1, NULL, start_mark, &prefix_value)) + goto error; + + /* Expect a whitespace or line break. */ + + if (!CACHE(parser, 1)) goto error; + + if (!IS_BLANKZ(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a %TAG directive", + start_mark, "did not find expected whitespace or line break"); + goto error; + } + + *handle = handle_value; + *prefix = prefix_value; + + return 1; + +error: + yaml_free(handle_value); + yaml_free(prefix_value); + return 0; +} + +static int +yaml_parser_scan_anchor(yaml_parser_t *parser, yaml_token_t *token, + yaml_token_type_t type) +{ + int length = 0; + yaml_mark_t start_mark, end_mark; + yaml_string_t string = NULL_STRING; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + + /* Eat the indicator character. */ + + start_mark = parser->mark; + + SKIP(parser); + + /* Consume the value. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_ALPHA(parser->buffer)) { + if (!READ(parser, string)) goto error; + if (!CACHE(parser, 1)) goto error; + length ++; + } + + end_mark = parser->mark; + + /* + * Check if length of the anchor is greater than 0 and it is followed by + * a whitespace character or one of the indicators: + * + * '?', ':', ',', ']', '}', '%', '@', '`'. + */ + + if (!length || !(IS_BLANKZ(parser->buffer) || CHECK(parser->buffer, '?') + || CHECK(parser->buffer, ':') || CHECK(parser->buffer, ',') + || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '}') + || CHECK(parser->buffer, '%') || CHECK(parser->buffer, '@') + || CHECK(parser->buffer, '`'))) { + yaml_parser_set_scanner_error(parser, type == YAML_ANCHOR_TOKEN ? + "while scanning an anchor" : "while scanning an alias", start_mark, + "did not find expected alphabetic or numeric character"); + goto error; + } + + /* Create a token. */ + + if (type == YAML_ANCHOR_TOKEN) { + ANCHOR_TOKEN_INIT(*token, string.start, start_mark, end_mark); + } + else { + ALIAS_TOKEN_INIT(*token, string.start, start_mark, end_mark); + } + + return 1; + +error: + STRING_DEL(parser, string); + return 0; +} + +/* + * Scan a TAG token. + */ + +static int +yaml_parser_scan_tag(yaml_parser_t *parser, yaml_token_t *token) +{ + yaml_char_t *handle = NULL; + yaml_char_t *suffix = NULL; + yaml_mark_t start_mark, end_mark; + + start_mark = parser->mark; + + /* Check if the tag is in the canonical form. */ + + if (!CACHE(parser, 2)) goto error; + + if (CHECK_AT(parser->buffer, '<', 1)) + { + /* Set the handle to '' */ + + handle = yaml_malloc(1); + if (!handle) goto error; + handle[0] = '\0'; + + /* Eat '!<' */ + + SKIP(parser); + SKIP(parser); + + /* Consume the tag value. */ + + if (!yaml_parser_scan_tag_uri(parser, 0, NULL, start_mark, &suffix)) + goto error; + + /* Check for '>' and eat it. */ + + if (!CHECK(parser->buffer, '>')) { + yaml_parser_set_scanner_error(parser, "while scanning a tag", + start_mark, "did not find the expected '>'"); + goto error; + } + + SKIP(parser); + } + else + { + /* The tag has either the '!suffix' or the '!handle!suffix' form. */ + + /* First, try to scan a handle. */ + + if (!yaml_parser_scan_tag_handle(parser, 0, start_mark, &handle)) + goto error; + + /* Check if it is, indeed, handle. */ + + if (handle[0] == '!' && handle[1] != '\0' && handle[strlen((char *)handle)-1] == '!') + { + /* Scan the suffix now. */ + + if (!yaml_parser_scan_tag_uri(parser, 0, NULL, start_mark, &suffix)) + goto error; + } + else + { + /* It wasn't a handle after all. Scan the rest of the tag. */ + + if (!yaml_parser_scan_tag_uri(parser, 0, handle, start_mark, &suffix)) + goto error; + + /* Set the handle to '!'. */ + + yaml_free(handle); + handle = yaml_malloc(2); + if (!handle) goto error; + handle[0] = '!'; + handle[1] = '\0'; + + /* + * A special case: the '!' tag. Set the handle to '' and the + * suffix to '!'. + */ + + if (suffix[0] == '\0') { + yaml_char_t *tmp = handle; + handle = suffix; + suffix = tmp; + } + } + } + + /* Check the character which ends the tag. */ + + if (!CACHE(parser, 1)) goto error; + + if (!IS_BLANKZ(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a tag", + start_mark, "did not find expected whitespace or line break"); + goto error; + } + + end_mark = parser->mark; + + /* Create a token. */ + + TAG_TOKEN_INIT(*token, handle, suffix, start_mark, end_mark); + + return 1; + +error: + yaml_free(handle); + yaml_free(suffix); + return 0; +} + +/* + * Scan a tag handle. + */ + +static int +yaml_parser_scan_tag_handle(yaml_parser_t *parser, int directive, + yaml_mark_t start_mark, yaml_char_t **handle) +{ + yaml_string_t string = NULL_STRING; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + + /* Check the initial '!' character. */ + + if (!CACHE(parser, 1)) goto error; + + if (!CHECK(parser->buffer, '!')) { + yaml_parser_set_scanner_error(parser, directive ? + "while scanning a tag directive" : "while scanning a tag", + start_mark, "did not find expected '!'"); + goto error; + } + + /* Copy the '!' character. */ + + if (!READ(parser, string)) goto error; + + /* Copy all subsequent alphabetical and numerical characters. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_ALPHA(parser->buffer)) + { + if (!READ(parser, string)) goto error; + if (!CACHE(parser, 1)) goto error; + } + + /* Check if the trailing character is '!' and copy it. */ + + if (CHECK(parser->buffer, '!')) + { + if (!READ(parser, string)) goto error; + } + else + { + /* + * It's either the '!' tag or not really a tag handle. If it's a %TAG + * directive, it's an error. If it's a tag token, it must be a part of + * URI. + */ + + if (directive && !(string.start[0] == '!' && string.start[1] == '\0')) { + yaml_parser_set_scanner_error(parser, "while parsing a tag directive", + start_mark, "did not find expected '!'"); + goto error; + } + } + + *handle = string.start; + + return 1; + +error: + STRING_DEL(parser, string); + return 0; +} + +/* + * Scan a tag. + */ + +static int +yaml_parser_scan_tag_uri(yaml_parser_t *parser, int directive, + yaml_char_t *head, yaml_mark_t start_mark, yaml_char_t **uri) +{ + size_t length = head ? strlen((char *)head) : 0; + yaml_string_t string = NULL_STRING; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + + /* Resize the string to include the head. */ + + while ((size_t)(string.end - string.start) <= length) { + if (!yaml_string_extend(&string.start, &string.pointer, &string.end)) { + parser->error = YAML_MEMORY_ERROR; + goto error; + } + } + + /* + * Copy the head if needed. + * + * Note that we don't copy the leading '!' character. + */ + + if (length > 1) { + memcpy(string.start, head+1, length-1); + string.pointer += length-1; + } + + /* Scan the tag. */ + + if (!CACHE(parser, 1)) goto error; + + /* + * The set of characters that may appear in URI is as follows: + * + * '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&', + * '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']', + * '%'. + */ + + while (IS_ALPHA(parser->buffer) || CHECK(parser->buffer, ';') + || CHECK(parser->buffer, '/') || CHECK(parser->buffer, '?') + || CHECK(parser->buffer, ':') || CHECK(parser->buffer, '@') + || CHECK(parser->buffer, '&') || CHECK(parser->buffer, '=') + || CHECK(parser->buffer, '+') || CHECK(parser->buffer, '$') + || CHECK(parser->buffer, ',') || CHECK(parser->buffer, '.') + || CHECK(parser->buffer, '!') || CHECK(parser->buffer, '~') + || CHECK(parser->buffer, '*') || CHECK(parser->buffer, '\'') + || CHECK(parser->buffer, '(') || CHECK(parser->buffer, ')') + || CHECK(parser->buffer, '[') || CHECK(parser->buffer, ']') + || CHECK(parser->buffer, '%')) + { + /* Check if it is a URI-escape sequence. */ + + if (CHECK(parser->buffer, '%')) { + if (!STRING_EXTEND(parser, string)) + goto error; + + if (!yaml_parser_scan_uri_escapes(parser, + directive, start_mark, &string)) goto error; + } + else { + if (!READ(parser, string)) goto error; + } + + length ++; + if (!CACHE(parser, 1)) goto error; + } + + /* Check if the tag is non-empty. */ + + if (!length) { + if (!STRING_EXTEND(parser, string)) + goto error; + + yaml_parser_set_scanner_error(parser, directive ? + "while parsing a %TAG directive" : "while parsing a tag", + start_mark, "did not find expected tag URI"); + goto error; + } + + *uri = string.start; + + return 1; + +error: + STRING_DEL(parser, string); + return 0; +} + +/* + * Decode an URI-escape sequence corresponding to a single UTF-8 character. + */ + +static int +yaml_parser_scan_uri_escapes(yaml_parser_t *parser, int directive, + yaml_mark_t start_mark, yaml_string_t *string) +{ + int width = 0; + + /* Decode the required number of characters. */ + + do { + + unsigned char octet = 0; + + /* Check for a URI-escaped octet. */ + + if (!CACHE(parser, 3)) return 0; + + if (!(CHECK(parser->buffer, '%') + && IS_HEX_AT(parser->buffer, 1) + && IS_HEX_AT(parser->buffer, 2))) { + return yaml_parser_set_scanner_error(parser, directive ? + "while parsing a %TAG directive" : "while parsing a tag", + start_mark, "did not find URI escaped octet"); + } + + /* Get the octet. */ + + octet = (AS_HEX_AT(parser->buffer, 1) << 4) + AS_HEX_AT(parser->buffer, 2); + + /* If it is the leading octet, determine the length of the UTF-8 sequence. */ + + if (!width) + { + width = (octet & 0x80) == 0x00 ? 1 : + (octet & 0xE0) == 0xC0 ? 2 : + (octet & 0xF0) == 0xE0 ? 3 : + (octet & 0xF8) == 0xF0 ? 4 : 0; + if (!width) { + return yaml_parser_set_scanner_error(parser, directive ? + "while parsing a %TAG directive" : "while parsing a tag", + start_mark, "found an incorrect leading UTF-8 octet"); + } + } + else + { + /* Check if the trailing octet is correct. */ + + if ((octet & 0xC0) != 0x80) { + return yaml_parser_set_scanner_error(parser, directive ? + "while parsing a %TAG directive" : "while parsing a tag", + start_mark, "found an incorrect trailing UTF-8 octet"); + } + } + + /* Copy the octet and move the pointers. */ + + *(string->pointer++) = octet; + SKIP(parser); + SKIP(parser); + SKIP(parser); + + } while (--width); + + return 1; +} + +/* + * Scan a block scalar. + */ + +static int +yaml_parser_scan_block_scalar(yaml_parser_t *parser, yaml_token_t *token, + int literal) +{ + yaml_mark_t start_mark; + yaml_mark_t end_mark; + yaml_string_t string = NULL_STRING; + yaml_string_t leading_break = NULL_STRING; + yaml_string_t trailing_breaks = NULL_STRING; + int chomping = 0; + int increment = 0; + int indent = 0; + int leading_blank = 0; + int trailing_blank = 0; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error; + + /* Eat the indicator '|' or '>'. */ + + start_mark = parser->mark; + + SKIP(parser); + + /* Scan the additional block scalar indicators. */ + + if (!CACHE(parser, 1)) goto error; + + /* Check for a chomping indicator. */ + + if (CHECK(parser->buffer, '+') || CHECK(parser->buffer, '-')) + { + /* Set the chomping method and eat the indicator. */ + + chomping = CHECK(parser->buffer, '+') ? +1 : -1; + + SKIP(parser); + + /* Check for an indentation indicator. */ + + if (!CACHE(parser, 1)) goto error; + + if (IS_DIGIT(parser->buffer)) + { + /* Check that the intendation is greater than 0. */ + + if (CHECK(parser->buffer, '0')) { + yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "found an intendation indicator equal to 0"); + goto error; + } + + /* Get the intendation level and eat the indicator. */ + + increment = AS_DIGIT(parser->buffer); + + SKIP(parser); + } + } + + /* Do the same as above, but in the opposite order. */ + + else if (IS_DIGIT(parser->buffer)) + { + if (CHECK(parser->buffer, '0')) { + yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "found an intendation indicator equal to 0"); + goto error; + } + + increment = AS_DIGIT(parser->buffer); + + SKIP(parser); + + if (!CACHE(parser, 1)) goto error; + + if (CHECK(parser->buffer, '+') || CHECK(parser->buffer, '-')) { + chomping = CHECK(parser->buffer, '+') ? +1 : -1; + + SKIP(parser); + } + } + + /* Eat whitespaces and comments to the end of the line. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_BLANK(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) goto error; + } + + if (CHECK(parser->buffer, '#')) { + while (!IS_BREAKZ(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) goto error; + } + } + + /* Check if we are at the end of the line. */ + + if (!IS_BREAKZ(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "did not find expected comment or line break"); + goto error; + } + + /* Eat a line break. */ + + if (IS_BREAK(parser->buffer)) { + if (!CACHE(parser, 2)) goto error; + SKIP_LINE(parser); + } + + end_mark = parser->mark; + + /* Set the intendation level if it was specified. */ + + if (increment) { + indent = parser->indent >= 0 ? parser->indent+increment : increment; + } + + /* Scan the leading line breaks and determine the indentation level if needed. */ + + if (!yaml_parser_scan_block_scalar_breaks(parser, &indent, &trailing_breaks, + start_mark, &end_mark)) goto error; + + /* Scan the block scalar content. */ + + if (!CACHE(parser, 1)) goto error; + + while ((int)parser->mark.column == indent && !IS_Z(parser->buffer)) + { + /* + * We are at the beginning of a non-empty line. + */ + + /* Is it a trailing whitespace? */ + + trailing_blank = IS_BLANK(parser->buffer); + + /* Check if we need to fold the leading line break. */ + + if (!literal && (*leading_break.start == '\n') + && !leading_blank && !trailing_blank) + { + /* Do we need to join the lines by space? */ + + if (*trailing_breaks.start == '\0') { + if (!STRING_EXTEND(parser, string)) goto error; + *(string.pointer ++) = ' '; + } + + CLEAR(parser, leading_break); + } + else { + if (!JOIN(parser, string, leading_break)) goto error; + CLEAR(parser, leading_break); + } + + /* Append the remaining line breaks. */ + + if (!JOIN(parser, string, trailing_breaks)) goto error; + CLEAR(parser, trailing_breaks); + + /* Is it a leading whitespace? */ + + leading_blank = IS_BLANK(parser->buffer); + + /* Consume the current line. */ + + while (!IS_BREAKZ(parser->buffer)) { + if (!READ(parser, string)) goto error; + if (!CACHE(parser, 1)) goto error; + } + + /* Consume the line break. */ + + if (!CACHE(parser, 2)) goto error; + + if (!READ_LINE(parser, leading_break)) goto error; + + /* Eat the following intendation spaces and line breaks. */ + + if (!yaml_parser_scan_block_scalar_breaks(parser, + &indent, &trailing_breaks, start_mark, &end_mark)) goto error; + } + + /* Chomp the tail. */ + + if (chomping != -1) { + if (!JOIN(parser, string, leading_break)) goto error; + } + if (chomping == 1) { + if (!JOIN(parser, string, trailing_breaks)) goto error; + } + + /* Create a token. */ + + SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start, + literal ? YAML_LITERAL_SCALAR_STYLE : YAML_FOLDED_SCALAR_STYLE, + start_mark, end_mark); + + STRING_DEL(parser, leading_break); + STRING_DEL(parser, trailing_breaks); + + return 1; + +error: + STRING_DEL(parser, string); + STRING_DEL(parser, leading_break); + STRING_DEL(parser, trailing_breaks); + + return 0; +} + +/* + * Scan intendation spaces and line breaks for a block scalar. Determine the + * intendation level if needed. + */ + +static int +yaml_parser_scan_block_scalar_breaks(yaml_parser_t *parser, + int *indent, yaml_string_t *breaks, + yaml_mark_t start_mark, yaml_mark_t *end_mark) +{ + int max_indent = 0; + + *end_mark = parser->mark; + + /* Eat the intendation spaces and line breaks. */ + + while (1) + { + /* Eat the intendation spaces. */ + + if (!CACHE(parser, 1)) return 0; + + while ((!*indent || (int)parser->mark.column < *indent) + && IS_SPACE(parser->buffer)) { + SKIP(parser); + if (!CACHE(parser, 1)) return 0; + } + + if ((int)parser->mark.column > max_indent) + max_indent = (int)parser->mark.column; + + /* Check for a tab character messing the intendation. */ + + if ((!*indent || (int)parser->mark.column < *indent) + && IS_TAB(parser->buffer)) { + return yaml_parser_set_scanner_error(parser, "while scanning a block scalar", + start_mark, "found a tab character where an intendation space is expected"); + } + + /* Have we found a non-empty line? */ + + if (!IS_BREAK(parser->buffer)) break; + + /* Consume the line break. */ + + if (!CACHE(parser, 2)) return 0; + if (!READ_LINE(parser, *breaks)) return 0; + *end_mark = parser->mark; + } + + /* Determine the indentation level if needed. */ + + if (!*indent) { + *indent = max_indent; + if (*indent < parser->indent + 1) + *indent = parser->indent + 1; + if (*indent < 1) + *indent = 1; + } + + return 1; +} + +/* + * Scan a quoted scalar. + */ + +static int +yaml_parser_scan_flow_scalar(yaml_parser_t *parser, yaml_token_t *token, + int single) +{ + yaml_mark_t start_mark; + yaml_mark_t end_mark; + yaml_string_t string = NULL_STRING; + yaml_string_t leading_break = NULL_STRING; + yaml_string_t trailing_breaks = NULL_STRING; + yaml_string_t whitespaces = NULL_STRING; + int leading_blanks; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, whitespaces, INITIAL_STRING_SIZE)) goto error; + + /* Eat the left quote. */ + + start_mark = parser->mark; + + SKIP(parser); + + /* Consume the content of the quoted scalar. */ + + while (1) + { + /* Check that there are no document indicators at the beginning of the line. */ + + if (!CACHE(parser, 4)) goto error; + + if (parser->mark.column == 0 && + ((CHECK_AT(parser->buffer, '-', 0) && + CHECK_AT(parser->buffer, '-', 1) && + CHECK_AT(parser->buffer, '-', 2)) || + (CHECK_AT(parser->buffer, '.', 0) && + CHECK_AT(parser->buffer, '.', 1) && + CHECK_AT(parser->buffer, '.', 2))) && + IS_BLANKZ_AT(parser->buffer, 3)) + { + yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", + start_mark, "found unexpected document indicator"); + goto error; + } + + /* Check for EOF. */ + + if (IS_Z(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a quoted scalar", + start_mark, "found unexpected end of stream"); + goto error; + } + + /* Consume non-blank characters. */ + + if (!CACHE(parser, 2)) goto error; + + leading_blanks = 0; + + while (!IS_BLANKZ(parser->buffer)) + { + /* Check for an escaped single quote. */ + + if (single && CHECK_AT(parser->buffer, '\'', 0) + && CHECK_AT(parser->buffer, '\'', 1)) + { + if (!STRING_EXTEND(parser, string)) goto error; + *(string.pointer++) = '\''; + SKIP(parser); + SKIP(parser); + } + + /* Check for the right quote. */ + + else if (CHECK(parser->buffer, single ? '\'' : '"')) + { + break; + } + + /* Check for an escaped line break. */ + + else if (!single && CHECK(parser->buffer, '\\') + && IS_BREAK_AT(parser->buffer, 1)) + { + if (!CACHE(parser, 3)) goto error; + SKIP(parser); + SKIP_LINE(parser); + leading_blanks = 1; + break; + } + + /* Check for an escape sequence. */ + + else if (!single && CHECK(parser->buffer, '\\')) + { + size_t code_length = 0; + + if (!STRING_EXTEND(parser, string)) goto error; + + /* Check the escape character. */ + + switch (parser->buffer.pointer[1]) + { + case '0': + *(string.pointer++) = '\0'; + break; + + case 'a': + *(string.pointer++) = '\x07'; + break; + + case 'b': + *(string.pointer++) = '\x08'; + break; + + case 't': + case '\t': + *(string.pointer++) = '\x09'; + break; + + case 'n': + *(string.pointer++) = '\x0A'; + break; + + case 'v': + *(string.pointer++) = '\x0B'; + break; + + case 'f': + *(string.pointer++) = '\x0C'; + break; + + case 'r': + *(string.pointer++) = '\x0D'; + break; + + case 'e': + *(string.pointer++) = '\x1B'; + break; + + case ' ': + *(string.pointer++) = '\x20'; + break; + + case '"': + *(string.pointer++) = '"'; + break; + + case '\'': + *(string.pointer++) = '\''; + break; + + case '\\': + *(string.pointer++) = '\\'; + break; + + case 'N': /* NEL (#x85) */ + *(string.pointer++) = '\xC2'; + *(string.pointer++) = '\x85'; + break; + + case '_': /* #xA0 */ + *(string.pointer++) = '\xC2'; + *(string.pointer++) = '\xA0'; + break; + + case 'L': /* LS (#x2028) */ + *(string.pointer++) = '\xE2'; + *(string.pointer++) = '\x80'; + *(string.pointer++) = '\xA8'; + break; + + case 'P': /* PS (#x2029) */ + *(string.pointer++) = '\xE2'; + *(string.pointer++) = '\x80'; + *(string.pointer++) = '\xA9'; + break; + + case 'x': + code_length = 2; + break; + + case 'u': + code_length = 4; + break; + + case 'U': + code_length = 8; + break; + + default: + yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", + start_mark, "found unknown escape character"); + goto error; + } + + SKIP(parser); + SKIP(parser); + + /* Consume an arbitrary escape code. */ + + if (code_length) + { + unsigned int value = 0; + size_t k; + + /* Scan the character value. */ + + if (!CACHE(parser, code_length)) goto error; + + for (k = 0; k < code_length; k ++) { + if (!IS_HEX_AT(parser->buffer, k)) { + yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", + start_mark, "did not find expected hexdecimal number"); + goto error; + } + value = (value << 4) + AS_HEX_AT(parser->buffer, k); + } + + /* Check the value and write the character. */ + + if ((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) { + yaml_parser_set_scanner_error(parser, "while parsing a quoted scalar", + start_mark, "found invalid Unicode character escape code"); + goto error; + } + + if (value <= 0x7F) { + *(string.pointer++) = value; + } + else if (value <= 0x7FF) { + *(string.pointer++) = 0xC0 + (value >> 6); + *(string.pointer++) = 0x80 + (value & 0x3F); + } + else if (value <= 0xFFFF) { + *(string.pointer++) = 0xE0 + (value >> 12); + *(string.pointer++) = 0x80 + ((value >> 6) & 0x3F); + *(string.pointer++) = 0x80 + (value & 0x3F); + } + else { + *(string.pointer++) = 0xF0 + (value >> 18); + *(string.pointer++) = 0x80 + ((value >> 12) & 0x3F); + *(string.pointer++) = 0x80 + ((value >> 6) & 0x3F); + *(string.pointer++) = 0x80 + (value & 0x3F); + } + + /* Advance the pointer. */ + + for (k = 0; k < code_length; k ++) { + SKIP(parser); + } + } + } + + else + { + /* It is a non-escaped non-blank character. */ + + if (!READ(parser, string)) goto error; + } + + if (!CACHE(parser, 2)) goto error; + } + + /* Check if we are at the end of the scalar. */ + + if (CHECK(parser->buffer, single ? '\'' : '"')) + break; + + /* Consume blank characters. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer)) + { + if (IS_BLANK(parser->buffer)) + { + /* Consume a space or a tab character. */ + + if (!leading_blanks) { + if (!READ(parser, whitespaces)) goto error; + } + else { + SKIP(parser); + } + } + else + { + if (!CACHE(parser, 2)) goto error; + + /* Check if it is a first line break. */ + + if (!leading_blanks) + { + CLEAR(parser, whitespaces); + if (!READ_LINE(parser, leading_break)) goto error; + leading_blanks = 1; + } + else + { + if (!READ_LINE(parser, trailing_breaks)) goto error; + } + } + if (!CACHE(parser, 1)) goto error; + } + + /* Join the whitespaces or fold line breaks. */ + + if (leading_blanks) + { + /* Do we need to fold line breaks? */ + + if (leading_break.start[0] == '\n') { + if (trailing_breaks.start[0] == '\0') { + if (!STRING_EXTEND(parser, string)) goto error; + *(string.pointer++) = ' '; + } + else { + if (!JOIN(parser, string, trailing_breaks)) goto error; + CLEAR(parser, trailing_breaks); + } + CLEAR(parser, leading_break); + } + else { + if (!JOIN(parser, string, leading_break)) goto error; + if (!JOIN(parser, string, trailing_breaks)) goto error; + CLEAR(parser, leading_break); + CLEAR(parser, trailing_breaks); + } + } + else + { + if (!JOIN(parser, string, whitespaces)) goto error; + CLEAR(parser, whitespaces); + } + } + + /* Eat the right quote. */ + + SKIP(parser); + + end_mark = parser->mark; + + /* Create a token. */ + + SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start, + single ? YAML_SINGLE_QUOTED_SCALAR_STYLE : YAML_DOUBLE_QUOTED_SCALAR_STYLE, + start_mark, end_mark); + + STRING_DEL(parser, leading_break); + STRING_DEL(parser, trailing_breaks); + STRING_DEL(parser, whitespaces); + + return 1; + +error: + STRING_DEL(parser, string); + STRING_DEL(parser, leading_break); + STRING_DEL(parser, trailing_breaks); + STRING_DEL(parser, whitespaces); + + return 0; +} + +/* + * Scan a plain scalar. + */ + +static int +yaml_parser_scan_plain_scalar(yaml_parser_t *parser, yaml_token_t *token) +{ + yaml_mark_t start_mark; + yaml_mark_t end_mark; + yaml_string_t string = NULL_STRING; + yaml_string_t leading_break = NULL_STRING; + yaml_string_t trailing_breaks = NULL_STRING; + yaml_string_t whitespaces = NULL_STRING; + int leading_blanks = 0; + int indent = parser->indent+1; + + if (!STRING_INIT(parser, string, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, leading_break, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, trailing_breaks, INITIAL_STRING_SIZE)) goto error; + if (!STRING_INIT(parser, whitespaces, INITIAL_STRING_SIZE)) goto error; + + start_mark = end_mark = parser->mark; + + /* Consume the content of the plain scalar. */ + + while (1) + { + /* Check for a document indicator. */ + + if (!CACHE(parser, 4)) goto error; + + if (parser->mark.column == 0 && + ((CHECK_AT(parser->buffer, '-', 0) && + CHECK_AT(parser->buffer, '-', 1) && + CHECK_AT(parser->buffer, '-', 2)) || + (CHECK_AT(parser->buffer, '.', 0) && + CHECK_AT(parser->buffer, '.', 1) && + CHECK_AT(parser->buffer, '.', 2))) && + IS_BLANKZ_AT(parser->buffer, 3)) break; + + /* Check for a comment. */ + + if (CHECK(parser->buffer, '#')) + break; + + /* Consume non-blank characters. */ + + while (!IS_BLANKZ(parser->buffer)) + { + /* Check for 'x:x' in the flow context. TODO: Fix the test "spec-08-13". */ + + if (parser->flow_level + && CHECK(parser->buffer, ':') + && !IS_BLANKZ_AT(parser->buffer, 1)) { + yaml_parser_set_scanner_error(parser, "while scanning a plain scalar", + start_mark, "found unexpected ':'"); + goto error; + } + + /* Check for indicators that may end a plain scalar. */ + + if ((CHECK(parser->buffer, ':') && IS_BLANKZ_AT(parser->buffer, 1)) + || (parser->flow_level && + (CHECK(parser->buffer, ',') || CHECK(parser->buffer, ':') + || CHECK(parser->buffer, '?') || CHECK(parser->buffer, '[') + || CHECK(parser->buffer, ']') || CHECK(parser->buffer, '{') + || CHECK(parser->buffer, '}')))) + break; + + /* Check if we need to join whitespaces and breaks. */ + + if (leading_blanks || whitespaces.start != whitespaces.pointer) + { + if (leading_blanks) + { + /* Do we need to fold line breaks? */ + + if (leading_break.start[0] == '\n') { + if (trailing_breaks.start[0] == '\0') { + if (!STRING_EXTEND(parser, string)) goto error; + *(string.pointer++) = ' '; + } + else { + if (!JOIN(parser, string, trailing_breaks)) goto error; + CLEAR(parser, trailing_breaks); + } + CLEAR(parser, leading_break); + } + else { + if (!JOIN(parser, string, leading_break)) goto error; + if (!JOIN(parser, string, trailing_breaks)) goto error; + CLEAR(parser, leading_break); + CLEAR(parser, trailing_breaks); + } + + leading_blanks = 0; + } + else + { + if (!JOIN(parser, string, whitespaces)) goto error; + CLEAR(parser, whitespaces); + } + } + + /* Copy the character. */ + + if (!READ(parser, string)) goto error; + + end_mark = parser->mark; + + if (!CACHE(parser, 2)) goto error; + } + + /* Is it the end? */ + + if (!(IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer))) + break; + + /* Consume blank characters. */ + + if (!CACHE(parser, 1)) goto error; + + while (IS_BLANK(parser->buffer) || IS_BREAK(parser->buffer)) + { + if (IS_BLANK(parser->buffer)) + { + /* Check for tab character that abuse intendation. */ + + if (leading_blanks && (int)parser->mark.column < indent + && IS_TAB(parser->buffer)) { + yaml_parser_set_scanner_error(parser, "while scanning a plain scalar", + start_mark, "found a tab character that violate intendation"); + goto error; + } + + /* Consume a space or a tab character. */ + + if (!leading_blanks) { + if (!READ(parser, whitespaces)) goto error; + } + else { + SKIP(parser); + } + } + else + { + if (!CACHE(parser, 2)) goto error; + + /* Check if it is a first line break. */ + + if (!leading_blanks) + { + CLEAR(parser, whitespaces); + if (!READ_LINE(parser, leading_break)) goto error; + leading_blanks = 1; + } + else + { + if (!READ_LINE(parser, trailing_breaks)) goto error; + } + } + if (!CACHE(parser, 1)) goto error; + } + + /* Check intendation level. */ + + if (!parser->flow_level && (int)parser->mark.column < indent) + break; + } + + /* Create a token. */ + + SCALAR_TOKEN_INIT(*token, string.start, string.pointer-string.start, + YAML_PLAIN_SCALAR_STYLE, start_mark, end_mark); + + /* Note that we change the 'simple_key_allowed' flag. */ + + if (leading_blanks) { + parser->simple_key_allowed = 1; + } + + STRING_DEL(parser, leading_break); + STRING_DEL(parser, trailing_breaks); + STRING_DEL(parser, whitespaces); + + return 1; + +error: + STRING_DEL(parser, string); + STRING_DEL(parser, leading_break); + STRING_DEL(parser, trailing_breaks); + STRING_DEL(parser, whitespaces); + + return 0; +} + diff --git a/src/external/yaml/writer.c b/src/external/yaml/writer.c new file mode 100644 index 0000000..b90019f --- /dev/null +++ b/src/external/yaml/writer.c @@ -0,0 +1,141 @@ + +#include "yaml_private.h" + +/* + * Declarations. + */ + +static int +yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem); + +YAML_DECLARE(int) +yaml_emitter_flush(yaml_emitter_t *emitter); + +/* + * Set the writer error and return 0. + */ + +static int +yaml_emitter_set_writer_error(yaml_emitter_t *emitter, const char *problem) +{ + emitter->error = YAML_WRITER_ERROR; + emitter->problem = problem; + + return 0; +} + +/* + * Flush the output buffer. + */ + +YAML_DECLARE(int) +yaml_emitter_flush(yaml_emitter_t *emitter) +{ + int low, high; + + assert(emitter); /* Non-NULL emitter object is expected. */ + assert(emitter->write_handler); /* Write handler must be set. */ + assert(emitter->encoding); /* Output encoding must be set. */ + + emitter->buffer.last = emitter->buffer.pointer; + emitter->buffer.pointer = emitter->buffer.start; + + /* Check if the buffer is empty. */ + + if (emitter->buffer.start == emitter->buffer.last) { + return 1; + } + + /* If the output encoding is UTF-8, we don't need to recode the buffer. */ + + if (emitter->encoding == YAML_UTF8_ENCODING) + { + if (emitter->write_handler(emitter->write_handler_data, + emitter->buffer.start, + emitter->buffer.last - emitter->buffer.start)) { + emitter->buffer.last = emitter->buffer.start; + emitter->buffer.pointer = emitter->buffer.start; + return 1; + } + else { + return yaml_emitter_set_writer_error(emitter, "write error"); + } + } + + /* Recode the buffer into the raw buffer. */ + + low = (emitter->encoding == YAML_UTF16LE_ENCODING ? 0 : 1); + high = (emitter->encoding == YAML_UTF16LE_ENCODING ? 1 : 0); + + while (emitter->buffer.pointer != emitter->buffer.last) + { + unsigned char octet; + unsigned int width; + unsigned int value; + size_t k; + + /* + * See the "reader.c" code for more details on UTF-8 encoding. Note + * that we assume that the buffer contains a valid UTF-8 sequence. + */ + + /* Read the next UTF-8 character. */ + + octet = emitter->buffer.pointer[0]; + + width = (octet & 0x80) == 0x00 ? 1 : + (octet & 0xE0) == 0xC0 ? 2 : + (octet & 0xF0) == 0xE0 ? 3 : + (octet & 0xF8) == 0xF0 ? 4 : 0; + + value = (octet & 0x80) == 0x00 ? octet & 0x7F : + (octet & 0xE0) == 0xC0 ? octet & 0x1F : + (octet & 0xF0) == 0xE0 ? octet & 0x0F : + (octet & 0xF8) == 0xF0 ? octet & 0x07 : 0; + + for (k = 1; k < width; k ++) { + octet = emitter->buffer.pointer[k]; + value = (value << 6) + (octet & 0x3F); + } + + emitter->buffer.pointer += width; + + /* Write the character. */ + + if (value < 0x10000) + { + emitter->raw_buffer.last[high] = value >> 8; + emitter->raw_buffer.last[low] = value & 0xFF; + + emitter->raw_buffer.last += 2; + } + else + { + /* Write the character using a surrogate pair (check "reader.c"). */ + + value -= 0x10000; + emitter->raw_buffer.last[high] = 0xD8 + (value >> 18); + emitter->raw_buffer.last[low] = (value >> 10) & 0xFF; + emitter->raw_buffer.last[high+2] = 0xDC + ((value >> 8) & 0xFF); + emitter->raw_buffer.last[low+2] = value & 0xFF; + + emitter->raw_buffer.last += 4; + } + } + + /* Write the raw buffer. */ + + if (emitter->write_handler(emitter->write_handler_data, + emitter->raw_buffer.start, + emitter->raw_buffer.last - emitter->raw_buffer.start)) { + emitter->buffer.last = emitter->buffer.start; + emitter->buffer.pointer = emitter->buffer.start; + emitter->raw_buffer.last = emitter->raw_buffer.start; + emitter->raw_buffer.pointer = emitter->raw_buffer.start; + return 1; + } + else { + return yaml_emitter_set_writer_error(emitter, "write error"); + } +} + diff --git a/src/external/yaml/yaml_private.h b/src/external/yaml/yaml_private.h new file mode 100644 index 0000000..3adaa05 --- /dev/null +++ b/src/external/yaml/yaml_private.h @@ -0,0 +1,661 @@ + +//#if HAVE_CONFIG_H +#include +//#endif + +#include + +#include +#include +#include + +#ifndef _MSC_VER +#include +#else +#ifdef _WIN64 +#define PTRDIFF_MAX _I64_MAX +#else +#define PTRDIFF_MAX INT_MAX +#endif +#endif + +/* + * Memory management. + */ + +YAML_DECLARE(void *) +yaml_malloc(size_t size); + +YAML_DECLARE(void *) +yaml_realloc(void *ptr, size_t size); + +YAML_DECLARE(void) +yaml_free(void *ptr); + +YAML_DECLARE(yaml_char_t *) +yaml_strdup(const yaml_char_t *); + +/* + * Reader: Ensure that the buffer contains at least `length` characters. + */ + +YAML_DECLARE(int) +yaml_parser_update_buffer(yaml_parser_t *parser, size_t length); + +/* + * Scanner: Ensure that the token stack contains at least one token ready. + */ + +YAML_DECLARE(int) +yaml_parser_fetch_more_tokens(yaml_parser_t *parser); + +/* + * The size of the input raw buffer. + */ + +#define INPUT_RAW_BUFFER_SIZE 16384 + +/* + * The size of the input buffer. + * + * It should be possible to decode the whole raw buffer. + */ + +#define INPUT_BUFFER_SIZE (INPUT_RAW_BUFFER_SIZE*3) + +/* + * The size of the output buffer. + */ + +#define OUTPUT_BUFFER_SIZE 16384 + +/* + * The size of the output raw buffer. + * + * It should be possible to encode the whole output buffer. + */ + +#define OUTPUT_RAW_BUFFER_SIZE (OUTPUT_BUFFER_SIZE*2+2) + +/* + * The size of other stacks and queues. + */ + +#define INITIAL_STACK_SIZE 16 +#define INITIAL_QUEUE_SIZE 16 +#define INITIAL_STRING_SIZE 16 + +/* + * Buffer management. + */ + +#define BUFFER_INIT(context,buffer,size) \ + (((buffer).start = yaml_malloc(size)) ? \ + ((buffer).last = (buffer).pointer = (buffer).start, \ + (buffer).end = (buffer).start+(size), \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define BUFFER_DEL(context,buffer) \ + (yaml_free((buffer).start), \ + (buffer).start = (buffer).pointer = (buffer).end = 0) + +/* + * String management. + */ + +typedef struct +{ + yaml_char_t *start; + yaml_char_t *end; + yaml_char_t *pointer; +} yaml_string_t; + +YAML_DECLARE(int) +yaml_string_extend(yaml_char_t **start, + yaml_char_t **pointer, yaml_char_t **end); + +YAML_DECLARE(int) +yaml_string_join( + yaml_char_t **a_start, yaml_char_t **a_pointer, yaml_char_t **a_end, + yaml_char_t **b_start, yaml_char_t **b_pointer, yaml_char_t **b_end); + +#define NULL_STRING { NULL, NULL, NULL } + +#define STRING(string,length) { (string), (string)+(length), (string) } + +#define STRING_ASSIGN(value,string,length) \ + ((value).start = (string), \ + (value).end = (string)+(length), \ + (value).pointer = (string)) + +#define STRING_INIT(context,string,size) \ + (((string).start = yaml_malloc(size)) ? \ + ((string).pointer = (string).start, \ + (string).end = (string).start+(size), \ + memset((string).start, 0, (size)), \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define STRING_DEL(context,string) \ + (yaml_free((string).start), \ + (string).start = (string).pointer = (string).end = 0) + +#define STRING_EXTEND(context,string) \ + ((((string).pointer+5 < (string).end) \ + || yaml_string_extend(&(string).start, \ + &(string).pointer, &(string).end)) ? \ + 1 : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define CLEAR(context,string) \ + ((string).pointer = (string).start, \ + memset((string).start, 0, (string).end-(string).start)) + +#define JOIN(context,string_a,string_b) \ + ((yaml_string_join(&(string_a).start, &(string_a).pointer, \ + &(string_a).end, &(string_b).start, \ + &(string_b).pointer, &(string_b).end)) ? \ + ((string_b).pointer = (string_b).start, \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +/* + * String check operations. + */ + +/* + * Check the octet at the specified position. + */ + +#define CHECK_AT(string,octet,offset) \ + ((string).pointer[offset] == (yaml_char_t)(octet)) + +/* + * Check the current octet in the buffer. + */ + +#define CHECK(string,octet) CHECK_AT((string),(octet),0) + +/* + * Check if the character at the specified position is an alphabetical + * character, a digit, '_', or '-'. + */ + +#define IS_ALPHA_AT(string,offset) \ + (((string).pointer[offset] >= (yaml_char_t) '0' && \ + (string).pointer[offset] <= (yaml_char_t) '9') || \ + ((string).pointer[offset] >= (yaml_char_t) 'A' && \ + (string).pointer[offset] <= (yaml_char_t) 'Z') || \ + ((string).pointer[offset] >= (yaml_char_t) 'a' && \ + (string).pointer[offset] <= (yaml_char_t) 'z') || \ + (string).pointer[offset] == '_' || \ + (string).pointer[offset] == '-') + +#define IS_ALPHA(string) IS_ALPHA_AT((string),0) + +/* + * Check if the character at the specified position is a digit. + */ + +#define IS_DIGIT_AT(string,offset) \ + (((string).pointer[offset] >= (yaml_char_t) '0' && \ + (string).pointer[offset] <= (yaml_char_t) '9')) + +#define IS_DIGIT(string) IS_DIGIT_AT((string),0) + +/* + * Get the value of a digit. + */ + +#define AS_DIGIT_AT(string,offset) \ + ((string).pointer[offset] - (yaml_char_t) '0') + +#define AS_DIGIT(string) AS_DIGIT_AT((string),0) + +/* + * Check if the character at the specified position is a hex-digit. + */ + +#define IS_HEX_AT(string,offset) \ + (((string).pointer[offset] >= (yaml_char_t) '0' && \ + (string).pointer[offset] <= (yaml_char_t) '9') || \ + ((string).pointer[offset] >= (yaml_char_t) 'A' && \ + (string).pointer[offset] <= (yaml_char_t) 'F') || \ + ((string).pointer[offset] >= (yaml_char_t) 'a' && \ + (string).pointer[offset] <= (yaml_char_t) 'f')) + +#define IS_HEX(string) IS_HEX_AT((string),0) + +/* + * Get the value of a hex-digit. + */ + +#define AS_HEX_AT(string,offset) \ + (((string).pointer[offset] >= (yaml_char_t) 'A' && \ + (string).pointer[offset] <= (yaml_char_t) 'F') ? \ + ((string).pointer[offset] - (yaml_char_t) 'A' + 10) : \ + ((string).pointer[offset] >= (yaml_char_t) 'a' && \ + (string).pointer[offset] <= (yaml_char_t) 'f') ? \ + ((string).pointer[offset] - (yaml_char_t) 'a' + 10) : \ + ((string).pointer[offset] - (yaml_char_t) '0')) + +#define AS_HEX(string) AS_HEX_AT((string),0) + +/* + * Check if the character is ASCII. + */ + +#define IS_ASCII_AT(string,offset) \ + ((string).pointer[offset] <= (yaml_char_t) '\x7F') + +#define IS_ASCII(string) IS_ASCII_AT((string),0) + +/* + * Check if the character can be printed unescaped. + */ + +#define IS_PRINTABLE_AT(string,offset) \ + (((string).pointer[offset] == 0x0A) /* . == #x0A */ \ + || ((string).pointer[offset] >= 0x20 /* #x20 <= . <= #x7E */ \ + && (string).pointer[offset] <= 0x7E) \ + || ((string).pointer[offset] == 0xC2 /* #0xA0 <= . <= #xD7FF */ \ + && (string).pointer[offset+1] >= 0xA0) \ + || ((string).pointer[offset] > 0xC2 \ + && (string).pointer[offset] < 0xED) \ + || ((string).pointer[offset] == 0xED \ + && (string).pointer[offset+1] < 0xA0) \ + || ((string).pointer[offset] == 0xEE) \ + || ((string).pointer[offset] == 0xEF /* #xE000 <= . <= #xFFFD */ \ + && !((string).pointer[offset+1] == 0xBB /* && . != #xFEFF */ \ + && (string).pointer[offset+2] == 0xBF) \ + && !((string).pointer[offset+1] == 0xBF \ + && ((string).pointer[offset+2] == 0xBE \ + || (string).pointer[offset+2] == 0xBF)))) + +#define IS_PRINTABLE(string) IS_PRINTABLE_AT((string),0) + +/* + * Check if the character at the specified position is NUL. + */ + +#define IS_Z_AT(string,offset) CHECK_AT((string),'\0',(offset)) + +#define IS_Z(string) IS_Z_AT((string),0) + +/* + * Check if the character at the specified position is BOM. + */ + +#define IS_BOM_AT(string,offset) \ + (CHECK_AT((string),'\xEF',(offset)) \ + && CHECK_AT((string),'\xBB',(offset)+1) \ + && CHECK_AT((string),'\xBF',(offset)+2)) /* BOM (#xFEFF) */ + +#define IS_BOM(string) IS_BOM_AT(string,0) + +/* + * Check if the character at the specified position is space. + */ + +#define IS_SPACE_AT(string,offset) CHECK_AT((string),' ',(offset)) + +#define IS_SPACE(string) IS_SPACE_AT((string),0) + +/* + * Check if the character at the specified position is tab. + */ + +#define IS_TAB_AT(string,offset) CHECK_AT((string),'\t',(offset)) + +#define IS_TAB(string) IS_TAB_AT((string),0) + +/* + * Check if the character at the specified position is blank (space or tab). + */ + +#define IS_BLANK_AT(string,offset) \ + (IS_SPACE_AT((string),(offset)) || IS_TAB_AT((string),(offset))) + +#define IS_BLANK(string) IS_BLANK_AT((string),0) + +/* + * Check if the character at the specified position is a line break. + */ + +#define IS_BREAK_AT(string,offset) \ + (CHECK_AT((string),'\r',(offset)) /* CR (#xD)*/ \ + || CHECK_AT((string),'\n',(offset)) /* LF (#xA) */ \ + || (CHECK_AT((string),'\xC2',(offset)) \ + && CHECK_AT((string),'\x85',(offset)+1)) /* NEL (#x85) */ \ + || (CHECK_AT((string),'\xE2',(offset)) \ + && CHECK_AT((string),'\x80',(offset)+1) \ + && CHECK_AT((string),'\xA8',(offset)+2)) /* LS (#x2028) */ \ + || (CHECK_AT((string),'\xE2',(offset)) \ + && CHECK_AT((string),'\x80',(offset)+1) \ + && CHECK_AT((string),'\xA9',(offset)+2))) /* PS (#x2029) */ + +#define IS_BREAK(string) IS_BREAK_AT((string),0) + +#define IS_CRLF_AT(string,offset) \ + (CHECK_AT((string),'\r',(offset)) && CHECK_AT((string),'\n',(offset)+1)) + +#define IS_CRLF(string) IS_CRLF_AT((string),0) + +/* + * Check if the character is a line break or NUL. + */ + +#define IS_BREAKZ_AT(string,offset) \ + (IS_BREAK_AT((string),(offset)) || IS_Z_AT((string),(offset))) + +#define IS_BREAKZ(string) IS_BREAKZ_AT((string),0) + +/* + * Check if the character is a line break, space, or NUL. + */ + +#define IS_SPACEZ_AT(string,offset) \ + (IS_SPACE_AT((string),(offset)) || IS_BREAKZ_AT((string),(offset))) + +#define IS_SPACEZ(string) IS_SPACEZ_AT((string),0) + +/* + * Check if the character is a line break, space, tab, or NUL. + */ + +#define IS_BLANKZ_AT(string,offset) \ + (IS_BLANK_AT((string),(offset)) || IS_BREAKZ_AT((string),(offset))) + +#define IS_BLANKZ(string) IS_BLANKZ_AT((string),0) + +/* + * Determine the width of the character. + */ + +#define WIDTH_AT(string,offset) \ + (((string).pointer[offset] & 0x80) == 0x00 ? 1 : \ + ((string).pointer[offset] & 0xE0) == 0xC0 ? 2 : \ + ((string).pointer[offset] & 0xF0) == 0xE0 ? 3 : \ + ((string).pointer[offset] & 0xF8) == 0xF0 ? 4 : 0) + +#define WIDTH(string) WIDTH_AT((string),0) + +/* + * Move the string pointer to the next character. + */ + +#define MOVE(string) ((string).pointer += WIDTH((string))) + +/* + * Copy a character and move the pointers of both strings. + */ + +#define COPY(string_a,string_b) \ + ((*(string_b).pointer & 0x80) == 0x00 ? \ + (*((string_a).pointer++) = *((string_b).pointer++)) : \ + (*(string_b).pointer & 0xE0) == 0xC0 ? \ + (*((string_a).pointer++) = *((string_b).pointer++), \ + *((string_a).pointer++) = *((string_b).pointer++)) : \ + (*(string_b).pointer & 0xF0) == 0xE0 ? \ + (*((string_a).pointer++) = *((string_b).pointer++), \ + *((string_a).pointer++) = *((string_b).pointer++), \ + *((string_a).pointer++) = *((string_b).pointer++)) : \ + (*(string_b).pointer & 0xF8) == 0xF0 ? \ + (*((string_a).pointer++) = *((string_b).pointer++), \ + *((string_a).pointer++) = *((string_b).pointer++), \ + *((string_a).pointer++) = *((string_b).pointer++), \ + *((string_a).pointer++) = *((string_b).pointer++)) : 0) + +/* + * Stack and queue management. + */ + +YAML_DECLARE(int) +yaml_stack_extend(void **start, void **top, void **end); + +YAML_DECLARE(int) +yaml_queue_extend(void **start, void **head, void **tail, void **end); + +#define STACK_INIT(context,stack,size) \ + (((stack).start = yaml_malloc((size)*sizeof(*(stack).start))) ? \ + ((stack).top = (stack).start, \ + (stack).end = (stack).start+(size), \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define STACK_DEL(context,stack) \ + (yaml_free((stack).start), \ + (stack).start = (stack).top = (stack).end = 0) + +#define STACK_EMPTY(context,stack) \ + ((stack).start == (stack).top) + +#define STACK_LIMIT(context,stack,size) \ + ((stack).top - (stack).start < (size) ? \ + 1 : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define PUSH(context,stack,value) \ + (((stack).top != (stack).end \ + || yaml_stack_extend((void **)&(stack).start, \ + (void **)&(stack).top, (void **)&(stack).end)) ? \ + (*((stack).top++) = value, \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define POP(context,stack) \ + (*(--(stack).top)) + +#define QUEUE_INIT(context,queue,size) \ + (((queue).start = yaml_malloc((size)*sizeof(*(queue).start))) ? \ + ((queue).head = (queue).tail = (queue).start, \ + (queue).end = (queue).start+(size), \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define QUEUE_DEL(context,queue) \ + (yaml_free((queue).start), \ + (queue).start = (queue).head = (queue).tail = (queue).end = 0) + +#define QUEUE_EMPTY(context,queue) \ + ((queue).head == (queue).tail) + +#define ENQUEUE(context,queue,value) \ + (((queue).tail != (queue).end \ + || yaml_queue_extend((void **)&(queue).start, (void **)&(queue).head, \ + (void **)&(queue).tail, (void **)&(queue).end)) ? \ + (*((queue).tail++) = value, \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +#define DEQUEUE(context,queue) \ + (*((queue).head++)) + +#define QUEUE_INSERT(context,queue,index,value) \ + (((queue).tail != (queue).end \ + || yaml_queue_extend((void **)&(queue).start, (void **)&(queue).head, \ + (void **)&(queue).tail, (void **)&(queue).end)) ? \ + (memmove((queue).head+(index)+1,(queue).head+(index), \ + ((queue).tail-(queue).head-(index))*sizeof(*(queue).start)), \ + *((queue).head+(index)) = value, \ + (queue).tail++, \ + 1) : \ + ((context)->error = YAML_MEMORY_ERROR, \ + 0)) + +/* + * Token initializers. + */ + +#define TOKEN_INIT(token,token_type,token_start_mark,token_end_mark) \ + (memset(&(token), 0, sizeof(yaml_token_t)), \ + (token).type = (token_type), \ + (token).start_mark = (token_start_mark), \ + (token).end_mark = (token_end_mark)) + +#define STREAM_START_TOKEN_INIT(token,token_encoding,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_STREAM_START_TOKEN,(start_mark),(end_mark)), \ + (token).data.stream_start.encoding = (token_encoding)) + +#define STREAM_END_TOKEN_INIT(token,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_STREAM_END_TOKEN,(start_mark),(end_mark))) + +#define ALIAS_TOKEN_INIT(token,token_value,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_ALIAS_TOKEN,(start_mark),(end_mark)), \ + (token).data.alias.value = (token_value)) + +#define ANCHOR_TOKEN_INIT(token,token_value,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_ANCHOR_TOKEN,(start_mark),(end_mark)), \ + (token).data.anchor.value = (token_value)) + +#define TAG_TOKEN_INIT(token,token_handle,token_suffix,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_TAG_TOKEN,(start_mark),(end_mark)), \ + (token).data.tag.handle = (token_handle), \ + (token).data.tag.suffix = (token_suffix)) + +#define SCALAR_TOKEN_INIT(token,token_value,token_length,token_style,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_SCALAR_TOKEN,(start_mark),(end_mark)), \ + (token).data.scalar.value = (token_value), \ + (token).data.scalar.length = (token_length), \ + (token).data.scalar.style = (token_style)) + +#define VERSION_DIRECTIVE_TOKEN_INIT(token,token_major,token_minor,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_VERSION_DIRECTIVE_TOKEN,(start_mark),(end_mark)), \ + (token).data.version_directive.major = (token_major), \ + (token).data.version_directive.minor = (token_minor)) + +#define TAG_DIRECTIVE_TOKEN_INIT(token,token_handle,token_prefix,start_mark,end_mark) \ + (TOKEN_INIT((token),YAML_TAG_DIRECTIVE_TOKEN,(start_mark),(end_mark)), \ + (token).data.tag_directive.handle = (token_handle), \ + (token).data.tag_directive.prefix = (token_prefix)) + +/* + * Event initializers. + */ + +#define EVENT_INIT(event,event_type,event_start_mark,event_end_mark) \ + (memset(&(event), 0, sizeof(yaml_event_t)), \ + (event).type = (event_type), \ + (event).start_mark = (event_start_mark), \ + (event).end_mark = (event_end_mark)) + +#define STREAM_START_EVENT_INIT(event,event_encoding,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_STREAM_START_EVENT,(start_mark),(end_mark)), \ + (event).data.stream_start.encoding = (event_encoding)) + +#define STREAM_END_EVENT_INIT(event,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_STREAM_END_EVENT,(start_mark),(end_mark))) + +#define DOCUMENT_START_EVENT_INIT(event,event_version_directive, \ + event_tag_directives_start,event_tag_directives_end,event_implicit,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_DOCUMENT_START_EVENT,(start_mark),(end_mark)), \ + (event).data.document_start.version_directive = (event_version_directive), \ + (event).data.document_start.tag_directives.start = (event_tag_directives_start), \ + (event).data.document_start.tag_directives.end = (event_tag_directives_end), \ + (event).data.document_start.implicit = (event_implicit)) + +#define DOCUMENT_END_EVENT_INIT(event,event_implicit,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_DOCUMENT_END_EVENT,(start_mark),(end_mark)), \ + (event).data.document_end.implicit = (event_implicit)) + +#define ALIAS_EVENT_INIT(event,event_anchor,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_ALIAS_EVENT,(start_mark),(end_mark)), \ + (event).data.alias.anchor = (event_anchor)) + +#define SCALAR_EVENT_INIT(event,event_anchor,event_tag,event_value,event_length, \ + event_plain_implicit, event_quoted_implicit,event_style,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_SCALAR_EVENT,(start_mark),(end_mark)), \ + (event).data.scalar.anchor = (event_anchor), \ + (event).data.scalar.tag = (event_tag), \ + (event).data.scalar.value = (event_value), \ + (event).data.scalar.length = (event_length), \ + (event).data.scalar.plain_implicit = (event_plain_implicit), \ + (event).data.scalar.quoted_implicit = (event_quoted_implicit), \ + (event).data.scalar.style = (event_style)) + +#define SEQUENCE_START_EVENT_INIT(event,event_anchor,event_tag, \ + event_implicit,event_style,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_SEQUENCE_START_EVENT,(start_mark),(end_mark)), \ + (event).data.sequence_start.anchor = (event_anchor), \ + (event).data.sequence_start.tag = (event_tag), \ + (event).data.sequence_start.implicit = (event_implicit), \ + (event).data.sequence_start.style = (event_style)) + +#define SEQUENCE_END_EVENT_INIT(event,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_SEQUENCE_END_EVENT,(start_mark),(end_mark))) + +#define MAPPING_START_EVENT_INIT(event,event_anchor,event_tag, \ + event_implicit,event_style,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_MAPPING_START_EVENT,(start_mark),(end_mark)), \ + (event).data.mapping_start.anchor = (event_anchor), \ + (event).data.mapping_start.tag = (event_tag), \ + (event).data.mapping_start.implicit = (event_implicit), \ + (event).data.mapping_start.style = (event_style)) + +#define MAPPING_END_EVENT_INIT(event,start_mark,end_mark) \ + (EVENT_INIT((event),YAML_MAPPING_END_EVENT,(start_mark),(end_mark))) + +/* + * Document initializer. + */ + +#define DOCUMENT_INIT(document,document_nodes_start,document_nodes_end, \ + document_version_directive,document_tag_directives_start, \ + document_tag_directives_end,document_start_implicit, \ + document_end_implicit,document_start_mark,document_end_mark) \ + (memset(&(document), 0, sizeof(yaml_document_t)), \ + (document).nodes.start = (document_nodes_start), \ + (document).nodes.end = (document_nodes_end), \ + (document).nodes.top = (document_nodes_start), \ + (document).version_directive = (document_version_directive), \ + (document).tag_directives.start = (document_tag_directives_start), \ + (document).tag_directives.end = (document_tag_directives_end), \ + (document).start_implicit = (document_start_implicit), \ + (document).end_implicit = (document_end_implicit), \ + (document).start_mark = (document_start_mark), \ + (document).end_mark = (document_end_mark)) + +/* + * Node initializers. + */ + +#define NODE_INIT(node,node_type,node_tag,node_start_mark,node_end_mark) \ + (memset(&(node), 0, sizeof(yaml_node_t)), \ + (node).type = (node_type), \ + (node).tag = (node_tag), \ + (node).start_mark = (node_start_mark), \ + (node).end_mark = (node_end_mark)) + +#define SCALAR_NODE_INIT(node,node_tag,node_value,node_length, \ + node_style,start_mark,end_mark) \ + (NODE_INIT((node),YAML_SCALAR_NODE,(node_tag),(start_mark),(end_mark)), \ + (node).data.scalar.value = (node_value), \ + (node).data.scalar.length = (node_length), \ + (node).data.scalar.style = (node_style)) + +#define SEQUENCE_NODE_INIT(node,node_tag,node_items_start,node_items_end, \ + node_style,start_mark,end_mark) \ + (NODE_INIT((node),YAML_SEQUENCE_NODE,(node_tag),(start_mark),(end_mark)), \ + (node).data.sequence.items.start = (node_items_start), \ + (node).data.sequence.items.end = (node_items_end), \ + (node).data.sequence.items.top = (node_items_start), \ + (node).data.sequence.style = (node_style)) + +#define MAPPING_NODE_INIT(node,node_tag,node_pairs_start,node_pairs_end, \ + node_style,start_mark,end_mark) \ + (NODE_INIT((node),YAML_MAPPING_NODE,(node_tag),(start_mark),(end_mark)), \ + (node).data.mapping.pairs.start = (node_pairs_start), \ + (node).data.mapping.pairs.end = (node_pairs_end), \ + (node).data.mapping.pairs.top = (node_pairs_start), \ + (node).data.mapping.style = (node_style)) + diff --git a/src/http/CurlHandlerPool.cpp b/src/http/CurlHandlerPool.cpp new file mode 100644 index 0000000..7e27372 --- /dev/null +++ b/src/http/CurlHandlerPool.cpp @@ -0,0 +1,90 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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 "plog/Log.h" +#include "http/CurlHandlerPool.h" + +bool CurlHandlerPool::Init() +{ + if (0 != pthread_mutex_init(&m_lock, NULL)) + { + LOGE << "Init curl handlers lock failed"; + return false; + } + m_handlers = new CURL*[m_maxHandlers](); + for (int i = 0; i < m_maxHandlers; ++i, ++m_index) + { + m_handlers[i] = curl_easy_init(); + if (!m_handlers[i]) + { + LOGE << "Init curl handlers pool failed"; + Destroy(); + return false; + } + } + return true; +} + +bool CurlHandlerPool::Destroy() +{ + for (int i = 0; i <= m_index; ++i) + { + curl_easy_cleanup(m_handlers[i]); + } + delete[] m_handlers; + if (0 != pthread_mutex_destroy(&m_lock)) + { + LOGE << "Destroy curl handlers lock failed"; + return false; + } + return true; +} + +CURL* CurlHandlerPool::GetHandler() +{ + CURL* handle = NULL; + pthread_mutex_lock(&m_lock); + if (m_index >= 0) + { + LOGD << "Get handler from pool: " << m_index; + handle = m_handlers[m_index--]; + } + pthread_mutex_unlock(&m_lock); + if (!handle) + { + LOGI << "Pool empty: create new handler"; + handle = curl_easy_init(); + } + return handle; +} + +void CurlHandlerPool::ReleaseHandler(CURL* handle) +{ + bool needCleanup = true; + pthread_mutex_lock(&m_lock); + if (m_index < m_maxHandlers - 1) + { + m_handlers[++m_index] = handle; + needCleanup = false; + LOGD << "Release handler to pool: %d", m_index; + } + pthread_mutex_unlock(&m_lock); + if (needCleanup) + { + LOGI << "Pool full: destroy the handler"; + curl_easy_cleanup(handle); + } +} \ No newline at end of file diff --git a/src/http/HttpClient.cpp b/src/http/HttpClient.cpp new file mode 100644 index 0000000..fc7c1b7 --- /dev/null +++ b/src/http/HttpClient.cpp @@ -0,0 +1,315 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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 "plog/Log.h" +#include "http/HttpClient.h" +#include "HttpCommon.h" +#include "http/HttpRequest.h" +#include "http/HttpResponse.h" +#include "StringUtils.h" +#include + +using namespace QingStor; +using namespace QingStor::Http; +using namespace QingStor::Utils; + +struct QsWriteCallbackContext +{ + QsWriteCallbackContext(const HttpClient *client, + HttpRequest *request, + HttpResponse *response) : m_client(client), + m_request(request), + m_response(response), + m_numBytesResponseReceived(0) {} + + const HttpClient *m_client; + HttpRequest *m_request; + HttpResponse *m_response; + int64_t m_numBytesResponseReceived; +}; + +struct QsReadCallbackContext +{ + QsReadCallbackContext(const HttpClient *client, HttpRequest *request) : m_client(client), m_request(request), m_hasBeenRead(0) {} + const HttpClient *m_client; + HttpRequest *m_request; + size_t m_hasBeenRead; +}; + +void SetOptCodeForHttpMethod(CURL *requestHandle, const HttpRequest &request) +{ + switch (request.GetMethod()) + { + case HTTP_GET: + curl_easy_setopt(requestHandle, CURLOPT_HTTPGET, 1L); + break; + case HTTP_PUT: + if (!request.HasHeader(CONTENT_LENGTH_HEADER) || request.GetHeaderValue(CONTENT_LENGTH_HEADER) == "0") + { + curl_easy_setopt(requestHandle, CURLOPT_CUSTOMREQUEST, "PUT"); + } + else + { + curl_easy_setopt(requestHandle, CURLOPT_PUT, 1L); + } + break; + case HTTP_POST: + if (!request.HasHeader(CONTENT_LENGTH_HEADER) || request.GetHeaderValue(CONTENT_LENGTH_HEADER) == "0") + { + curl_easy_setopt(requestHandle, CURLOPT_CUSTOMREQUEST, "POST"); + } + else + { + curl_easy_setopt(requestHandle, CURLOPT_POST, 1L); + } + break; + case HTTP_HEAD: + curl_easy_setopt(requestHandle, CURLOPT_HTTPGET, 1L); + curl_easy_setopt(requestHandle, CURLOPT_NOBODY, 1L); + break; + case HTTP_DELETE: + curl_easy_setopt(requestHandle, CURLOPT_CUSTOMREQUEST, "DELETE"); + break; + case HTTP_PATCH: + if (!request.HasHeader(CONTENT_LENGTH_HEADER) || request.GetHeaderValue(CONTENT_LENGTH_HEADER) == "0") + { + curl_easy_setopt(requestHandle, CURLOPT_CUSTOMREQUEST, "PATCH"); + } + else + { + curl_easy_setopt(requestHandle, CURLOPT_POST, 1L); + curl_easy_setopt(requestHandle, CURLOPT_CUSTOMREQUEST, "PATCH"); + } + break; + default: + curl_easy_setopt(requestHandle, CURLOPT_CUSTOMREQUEST, "GET"); + break; + } +} + +void HttpClient::CreateGlobaleCurlPool() +{ + gCurlPool = new CurlHandlerPool(gCurlPoolSize); + if (!gCurlPool->Init()) + { + LOG_FATAL << "Create CurlPool faild..."; + } +} + +void HttpClient::DestroyGlobaleCurlPool() +{ + if(!gCurlPool) + { + return; + } + if(!gCurlPool->Destroy()) + { + LOG_FATAL << "Festroy CurlPool faild..."; + } + delete gCurlPool; + gCurlPool = NULL; +} + +HttpResponse * HttpClient::SendRequest(HttpRequest *request) const +{ + std::string url = request->GetURIString(); + LOG_DEBUG << "Making request to " << url; + struct curl_slist *headers = NULL; + std::stringstream headerStream; + HeaderValueCollection requestHeaders = request->GetHeaders(); + for(HeaderValueCollection::iterator it = requestHeaders.begin(); it != requestHeaders.end(); it++) + { + headerStream.str(""); + headerStream << it->first << ":" << it->second; + std::string headerString = headerStream.str(); + LOG_DEBUG << "Including header:" << headerString; + headers = curl_slist_append(headers, headerString.c_str()); + } + headers = curl_slist_append(headers, "transfer-encoding:"); + if (!request->HasHeader(Http::CONTENT_LENGTH_HEADER)) + { + headers = curl_slist_append(headers, "content-length:"); + } + if (!request->HasHeader(Http::CONTENT_TYPE_HEADER)) + { + headers = curl_slist_append(headers, "content-type:"); + } + HttpResponse * response = NULL; + CURL * connectionHandle = gCurlPool->GetHandler(); + if (connectionHandle) + { + curl_easy_reset(connectionHandle); + LOG_DEBUG << "Obtained connection handle: " << connectionHandle; + if (headers) + { + curl_easy_setopt(connectionHandle, CURLOPT_HTTPHEADER, headers); + } + response = new HttpResponse(); + QsWriteCallbackContext writeContext(this, request, response); + QsReadCallbackContext readContext(this, request); + SetOptCodeForHttpMethod(connectionHandle, *request); + curl_easy_setopt(connectionHandle, CURLOPT_TCP_NODELAY, 1L); + curl_easy_setopt(connectionHandle, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(connectionHandle, CURLOPT_TIMEOUT, 600L); + if(m_timeOutPeriod > 0) + { + curl_easy_setopt(connectionHandle, CURLOPT_CONNECTTIMEOUT, m_timeOutPeriod); + } + else + { + curl_easy_setopt(connectionHandle, CURLOPT_CONNECTTIMEOUT, 3); + } + curl_easy_setopt(connectionHandle, CURLOPT_URL, url.c_str()); + curl_easy_setopt(connectionHandle, CURLOPT_WRITEFUNCTION, &HttpClient::WriteData); + curl_easy_setopt(connectionHandle, CURLOPT_WRITEDATA, &writeContext); + curl_easy_setopt(connectionHandle, CURLOPT_HEADERFUNCTION, &HttpClient::WriteHeader); + curl_easy_setopt(connectionHandle, CURLOPT_HEADERDATA, response); + curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(connectionHandle, CURLOPT_SSL_VERIFYHOST, 0L); + curl_easy_setopt(connectionHandle, CURLOPT_FOLLOWLOCATION, 0L); + // If config enable Curl dbg option, print to stdin. + if (plog::get() && plog::get()->checkSeverity(plog::verbose)) + { + curl_easy_setopt(connectionHandle, CURLOPT_VERBOSE, true); + } + if (request->GetContentBody()) + { + curl_easy_setopt(connectionHandle, CURLOPT_READFUNCTION, &HttpClient::ReadBody); + curl_easy_setopt(connectionHandle, CURLOPT_READDATA, &readContext); + } + CURLcode curlResponseCode = curl_easy_perform(connectionHandle); + if (curlResponseCode != CURLE_OK) + { + if(response) + { + response->ReleaseResponseBody(); + delete response; + response = NULL; + } + LOG_DEBUG << "Curl returned error code: " << curlResponseCode; + } + else + { + long responseCode; + curl_easy_getinfo(connectionHandle, CURLINFO_RESPONSE_CODE, &responseCode); + response->SetResponseCode(static_cast(responseCode)); + LOG_DEBUG << "Returned http response code: " << responseCode; + char *contentType = NULL; + curl_easy_getinfo(connectionHandle, CURLINFO_CONTENT_TYPE, &contentType); + if (contentType) + { + response->SetContentType(contentType); + LOG_DEBUG << "Returned content type: " << contentType; + } + if (request->GetMethod() != HTTP_HEAD && + response->HasHeader(CONTENT_LENGTH_HEADER)) + { + const std::string &contentLength = response->GetHeader(CONTENT_LENGTH_HEADER); + int64_t numBytesResponseReceived = writeContext.m_numBytesResponseReceived; + LOG_DEBUG << "Response content-length header: " << contentLength; + LOG_DEBUG << "Response body length: " << numBytesResponseReceived; + if (StringUtils::ConvertToInt64(contentLength.c_str()) != numBytesResponseReceived) + { + if(response) + { + response->ReleaseResponseBody(); + delete response; + response = NULL; + } + LOG_DEBUG << "Response body length doesn't match the content-length header."; + } + } + LOG_DEBUG << "Releasing curl handle: " << connectionHandle; + } + gCurlPool->ReleaseHandler(connectionHandle); + connectionHandle = NULL; + //go ahead and flush the response body stream + if (response) + { + response->GetResponseBody()->flush(); + } + } + if (headers) + { + curl_slist_free_all(headers); + } + return response; +} + +size_t HttpClient::WriteData(char *ptr, size_t size, size_t nmemb, void *userdata) +{ + if (ptr) + { + QsWriteCallbackContext *context = reinterpret_cast(userdata); + HttpResponse *response = context->m_response; + size_t sizeToWrite = size * nmemb; + response->GetResponseBody()->write(ptr, static_cast(sizeToWrite)); + LOG_DEBUG << sizeToWrite << " bytes written to response."; + context->m_numBytesResponseReceived += sizeToWrite; + return sizeToWrite; + } + return 0; +} + +size_t HttpClient::WriteHeader(char *ptr, size_t size, size_t nmemb, void *userdata) +{ + if (ptr) + { + HttpResponse *response = (HttpResponse *)userdata; + std::string headerLine(ptr); + std::vector keyValuePair = StringUtils::Split(headerLine, ':'); + if (keyValuePair.size() > 1) + { + std::string headerName = keyValuePair[0]; + headerName = StringUtils::Trim(headerName.c_str()); + std::string headerValue = headerLine.substr(headerName.length() + 1).c_str(); + headerValue = StringUtils::Trim(headerValue.c_str()); + response->AddHeader(headerName, headerValue); + } + return size * nmemb; + } + return 0; +} + +size_t HttpClient::ReadBody(char *ptr, size_t size, size_t nmemb, void *userdata) +{ + QsReadCallbackContext *context = reinterpret_cast(userdata); + if (context == NULL) + { + return 0; + } + HttpRequest *request = context->m_request; + std::iostream * ioStream = request->GetContentBody(); + if (ioStream != NULL && size * nmemb) + { + size_t amountToRead = size * nmemb; + size_t needToRead = 0; + std::string contentLength = request->GetHeaderValue("Content-Length"); + if ("" != contentLength) + { + needToRead = Utils::StringUtils::ConvertToInt64(contentLength.c_str()) - context->m_hasBeenRead; + } + if (0 != amountToRead && needToRead < amountToRead) + { + amountToRead = needToRead; + } + ioStream->read(ptr, amountToRead); + size_t amountRead = static_cast(ioStream->gcount()); + context->m_hasBeenRead += amountRead; + return amountRead; + } + return 0; +} diff --git a/src/http/HttpCommon.cpp b/src/http/HttpCommon.cpp new file mode 100644 index 0000000..8785ce6 --- /dev/null +++ b/src/http/HttpCommon.cpp @@ -0,0 +1,94 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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 "HttpCommon.h" + +namespace QingStor +{ +namespace Http +{ +namespace HttpMethodMapper +{ +const char *GetNameForHttpMethod(HttpMethod httpMethod) +{ + switch (httpMethod) + { + case HTTP_GET: + return "GET"; + case HTTP_POST: + return "POST"; + case HTTP_DELETE: + return "DELETE"; + case HTTP_PUT: + return "PUT"; + case HTTP_HEAD: + return "HEAD"; + case HTTP_PATCH: + return "PATCH"; + default: + return "GET"; + } +} +} + +namespace SchemeMapper +{ + +/** +* Converts a Scheme instance to a String. +*/ +QS_SDK_API const char *ToString(Scheme scheme) +{ + switch (scheme) + { + case HTTP: + return "http"; + case HTTPS: + return "https"; + default: + return "http"; + } +} + +/** +* Converts a string instance to a Scheme. Defaults to https. +*/ +QS_SDK_API Scheme FromString(const char *name) +{ + std::string trimmedString = QingStor::Utils::StringUtils::Trim(name); + std::string loweredTrimmedString = QingStor::Utils::StringUtils::ToLower(trimmedString.c_str()); + if (loweredTrimmedString == "http") + { + return HTTP; + } + //this branch is technically unneeded, but it is here so we don't have a subtle bug + //creep in as we extend this enum. + else if (loweredTrimmedString == "https") + { + return HTTPS; + } + return HTTPS; +} +} // namespace SchemeMapper + +const char *DATE_HEADER = "Date"; +const char *CONTENT_LENGTH_HEADER = "Content-Length"; +const char *CONTENT_TYPE_HEADER = "Content-Type"; +const char *CONTENT_MD5_HEADER = "Content-MD5"; +const char *AUTHORIZATION_HEADER = "Authorization"; + +} // namespace Http +} // namespace QingStor diff --git a/src/http/HttpRequest.cpp b/src/http/HttpRequest.cpp new file mode 100644 index 0000000..e35fedb --- /dev/null +++ b/src/http/HttpRequest.cpp @@ -0,0 +1,76 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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 "http/HttpRequest.h" +#include "StringUtils.h" +#include + +using namespace QingStor::Utils; +using namespace QingStor::Http; + +HttpRequest::HttpRequest(HttpMethod method, URI uri) + : bodyStream(NULL), m_uri(uri), m_method(method), headerMap() +{ + std::string queryString = uri.GetQueryString(); + if("" != queryString) + { + SetQueryStringParameter(queryString.substr(1, queryString.length()), ""); + } +} + +const std::string HttpRequest::GetHeaderValue(const char* headerName) const +{ + if (headerMap.find(StringUtils::ToLower(headerName)) != headerMap.end()) + { + return headerMap.find(StringUtils::ToLower(headerName))->second; + } + else + { + return ""; + } +} + +void HttpRequest::SetHeaderValue(const char* headerName, const std::string& headerValue) +{ + headerMap[StringUtils::ToLower(headerName)] = StringUtils::Trim(headerValue.c_str()); +} + +void HttpRequest::SetHeaderValue(const std::string& headerName, const std::string& headerValue) +{ + headerMap[StringUtils::ToLower(headerName.c_str())] = StringUtils::Trim(headerValue.c_str()); +} + +void HttpRequest::SetQueryStringParameter(const char* name, const std::string& value) +{ + queryMap[StringUtils::ToLower(name)] = StringUtils::Trim(value.c_str()); + m_uri.AddQueryStringParameter(name, value); +} + +void HttpRequest::SetQueryStringParameter(const std::string& name, const std::string& value) +{ + queryMap[StringUtils::ToLower(name.c_str())] = StringUtils::Trim(value.c_str()); + m_uri.AddQueryStringParameter(name.c_str(), value); +} + +void HttpRequest::DeleteHeader(const char* headerName) +{ + headerMap.erase(StringUtils::ToLower(headerName)); +} + +bool HttpRequest::HasHeader(const char* headerName) const +{ + return headerMap.find(StringUtils::ToLower(headerName)) != headerMap.end(); +} diff --git a/src/http/HttpResponse.cpp b/src/http/HttpResponse.cpp new file mode 100644 index 0000000..cba34d0 --- /dev/null +++ b/src/http/HttpResponse.cpp @@ -0,0 +1,51 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or at: +// | +// | http://www.apache.org/licenses/LICENSE-2.0 +// | +// | Unless required by applicable law or agreed to in writing, software +// | distributed under the License is distributed on an "AS IS" BASIS, +// | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// | See the License for the specific language governing permissions and +// | limitations under the License. +// +------------------------------------------------------------------------- + +#include +#include "HttpCommon.h" +#include "StringUtils.h" +#include + +using namespace QingStor::Http; +using namespace QingStor::Utils; + +HeaderValueCollection HttpResponse::GetHeaders() +{ + return headerMap; +} + +bool HttpResponse::HasHeader(const char *headerName) const +{ + return headerMap.find(StringUtils::ToLower(headerName)) != headerMap.end(); +} + +std::string HttpResponse::GetHeader(const std::string &headerName) const +{ + std::map::const_iterator foundValue = headerMap.find(StringUtils::ToLower(headerName.c_str())); + if (foundValue == headerMap.end()) + { + return ""; + } + else + { + return foundValue->second; + } +} + +void HttpResponse::AddHeader(const std::string &headerName, const std::string &headerValue) +{ + headerMap[StringUtils::ToLower(headerName.c_str())] = headerValue; +} diff --git a/src/http/HttpURI.cpp b/src/http/HttpURI.cpp new file mode 100644 index 0000000..bf88725 --- /dev/null +++ b/src/http/HttpURI.cpp @@ -0,0 +1,87 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or at: +// | +// | http://www.apache.org/licenses/LICENSE-2.0 +// | +// | Unless required by applicable law or agreed to in writing, software +// | distributed under the License is distributed on an "AS IS" BASIS, +// | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// | See the License for the specific language governing permissions and +// | limitations under the License. +// +------------------------------------------------------------------------- + +#include +#include "HttpCommon.h" +#include "StringUtils.h" +#include +#include +#include +#include +#include + +using namespace QingStor::Http; +using namespace QingStor::Utils; + +namespace QingStor +{ +namespace Http +{ +const char *SEPARATOR = "://"; +} +} // namespace QingStor + +URI::URI(const std::string &endpoint, const std::string &path, const std::string &queryString) : m_endpoint(endpoint), m_path(path), m_queryString(queryString) +{ +} + +std::string URI::URLEncodePath(const std::string &path) +{ + std::vector pathParts = StringUtils::Split(path, '/'); + std::stringstream ss; + for (std::vector::iterator iter = pathParts.begin(); iter != pathParts.end(); ++iter) + { + ss << '/' << StringUtils::URLEncode(iter->c_str()); + } + //if the last character was also a slash, then add that back here. + if ("" != path && path[path.length() - 1] == '/') + { + ss << '/'; + } + return ss.str(); +} + +void URI::AddQueryStringParameter(const char *key, const std::string &value) +{ + if (m_queryString.size() <= 0) + { + m_queryString.append("?"); + } + else + { + m_queryString.append("&"); + } + m_queryString.append(StringUtils::URLEncode(key) + "=" + StringUtils::URLEncode(value.c_str())); +} + +std::string URI::GetURIString() const +{ + std::stringstream ss; + ss << m_endpoint << URLEncodePath(m_path) << m_queryString; + return ss.str(); +} + +std::string URI::GetFormParameters() const +{ + if (m_queryString.length() == 0) + { + return ""; + } + else + { + return m_queryString.substr(1); + } +} diff --git a/src/include/external/json/allocator.h b/src/include/external/json/allocator.h new file mode 100644 index 0000000..a3e0624 --- /dev/null +++ b/src/include/external/json/allocator.h @@ -0,0 +1,112 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// 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_ALLOCATOR_H_INCLUDED +#define CPPTL_JSON_ALLOCATOR_H_INCLUDED + +#include +#include + +#pragma pack(push, 8) + +namespace Json +{ +template +class SecureAllocator +{ +public: + // Type definitions + using value_type = T; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + /** + * Allocate memory for N items using the standard allocator. + */ + pointer allocate(size_type n) + { + // allocate using "global operator new" + return static_cast(::operator new(n * sizeof(T))); + } + + /** + * Release memory which was allocated for N items at pointer P. + * + * The memory block is filled with zeroes before being released. + * The pointer argument is tagged as "volatile" to prevent the + * compiler optimizing out this critical step. + */ + void deallocate(volatile pointer p, size_type n) + { + std::memset(p, 0, n * sizeof(T)); + // free using "global operator delete" + ::operator delete(p); + } + + /** + * Construct an item in-place at pointer P. + */ + template + void construct(pointer p, Args&&... args) + { + // construct using "placement new" and "perfect forwarding" + ::new (static_cast(p)) T(std::forward(args)...); + } + + size_type max_size() const + { + return size_t(-1) / sizeof(T); + } + + pointer address( reference x ) const + { + return std::addressof(x); + } + + const_pointer address( const_reference x ) const + { + return std::addressof(x); + } + + /** + * Destroy an item in-place at pointer P. + */ + void destroy(pointer p) + { + // destroy using "explicit destructor" + p->~T(); + } + + // Boilerplate + SecureAllocator() {} + template SecureAllocator(const SecureAllocator&) {} + template struct rebind + { + using other = SecureAllocator; + }; +}; + + +template +bool operator==(const SecureAllocator&, const SecureAllocator&) +{ + return true; +} + +template +bool operator!=(const SecureAllocator&, const SecureAllocator&) +{ + return false; +} + +} //namespace Json + +#pragma pack(pop) + +#endif // CPPTL_JSON_ALLOCATOR_H_INCLUDED diff --git a/src/include/external/json/assertions.h b/src/include/external/json/assertions.h new file mode 100644 index 0000000..1cca28d --- /dev/null +++ b/src/include/external/json/assertions.h @@ -0,0 +1,54 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// 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) \ + { \ + JSONCPP_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) \ + { \ + JSONCPP_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 diff --git a/src/include/external/json/autolink.h b/src/include/external/json/autolink.h new file mode 100644 index 0000000..b2c0f00 --- /dev/null +++ b/src/include/external/json/autolink.h @@ -0,0 +1,25 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// 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_AUTOLINK_H_INCLUDED +#define JSON_AUTOLINK_H_INCLUDED + +#include "config.h" + +#ifdef JSON_IN_CPPTL +#include +#endif + +#if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && \ + !defined(JSON_IN_CPPTL) +#define CPPTL_AUTOLINK_NAME "json" +#undef CPPTL_AUTOLINK_DLL +#ifdef JSON_DLL +#define CPPTL_AUTOLINK_DLL +#endif +#include "autolink.h" +#endif + +#endif // JSON_AUTOLINK_H_INCLUDED diff --git a/src/include/external/json/config.h b/src/include/external/json/config.h new file mode 100644 index 0000000..f782273 --- /dev/null +++ b/src/include/external/json/config.h @@ -0,0 +1,188 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// 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 +#include +#include //typedef String +#include //typedef int64_t, uint64_t + +/// 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) || defined(__MINGW32__) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#elif defined(JSON_DLL) +#if defined(_MSC_VER) || defined(__MINGW32__) +#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) // MSVC +# if _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 // MSVC 6 + +# if _MSC_VER >= 1500 // MSVC 2008 +/// Indicates that the following function is deprecated. +# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +# endif + +#endif // defined(_MSC_VER) + +// In c++11 the override keyword allows you to explicity define that a function +// is intended to override the base-class version. This makes the code more +// managable and fixes a set of common hard-to-find bugs. +#if __cplusplus >= 201103L +# define JSONCPP_OVERRIDE override +# define JSONCPP_NOEXCEPT noexcept +#elif defined(_MSC_VER) && _MSC_VER > 1600 && _MSC_VER < 1900 +# define JSONCPP_OVERRIDE override +# define JSONCPP_NOEXCEPT throw() +#elif defined(_MSC_VER) && _MSC_VER >= 1900 +# define JSONCPP_OVERRIDE override +# define JSONCPP_NOEXCEPT noexcept +#else +# define JSONCPP_OVERRIDE +# define JSONCPP_NOEXCEPT throw() +#endif + +#ifndef JSON_HAS_RVALUE_REFERENCES + +#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // MSVC >= 2010 + +#ifdef __clang__ +#if __has_feature(cxx_rvalue_references) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // has_feature + +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // GXX_EXPERIMENTAL + +#endif // __clang__ || __GNUC__ + +#endif // not defined JSON_HAS_RVALUE_REFERENCES + +#ifndef JSON_HAS_RVALUE_REFERENCES +#define JSON_HAS_RVALUE_REFERENCES 0 +#endif + +#ifdef __clang__ +# if __has_extension(attribute_deprecated_with_message) +# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# endif +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +# define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +# endif // GNUC version +#endif // __clang__ || __GNUC__ + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +#if __GNUC__ >= 6 +# define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +# include "version.h" + +# if JSONCPP_USING_SECURE_MEMORY +# include "allocator.h" //typedef Allocator +# endif + +#endif // if !defined(JSON_IS_AMALGAMATION) + +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 int64_t Int64; +typedef uint64_t UInt64; +#endif // if defined(_MSC_VER) +typedef Int64 LargestInt; +typedef UInt64 LargestUInt; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) +#if JSONCPP_USING_SECURE_MEMORY +#define JSONCPP_STRING std::basic_string, Json::SecureAllocator > +#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream, Json::SecureAllocator > +#define JSONCPP_OSTREAM std::basic_ostream> +#define JSONCPP_ISTRINGSTREAM std::basic_istringstream, Json::SecureAllocator > +#define JSONCPP_ISTREAM std::istream +#else +#define JSONCPP_STRING std::string +#define JSONCPP_OSTRINGSTREAM std::ostringstream +#define JSONCPP_OSTREAM std::ostream +#define JSONCPP_ISTRINGSTREAM std::istringstream +#define JSONCPP_ISTREAM std::istream +#endif // if JSONCPP_USING_SECURE_MEMORY +} // end namespace Json + +#endif // JSON_CONFIG_H_INCLUDED diff --git a/src/include/external/json/features.h b/src/include/external/json/features.h new file mode 100644 index 0000000..c8b7d54 --- /dev/null +++ b/src/include/external/json/features.h @@ -0,0 +1,63 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// 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) + +#pragma pack(push, 8) + +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_; + + /// \c true if dropped null placeholders are allowed. Default: \c false. + bool allowDroppedNullPlaceholders_; + + /// \c true if numeric object key are allowed. Default: \c false. + bool allowNumericKeys_; +}; + +} // namespace Json + +#pragma pack(pop) + +#endif // CPPTL_JSON_FEATURES_H_INCLUDED diff --git a/src/include/external/json/forwards.h b/src/include/external/json/forwards.h new file mode 100644 index 0000000..84b67d6 --- /dev/null +++ b/src/include/external/json/forwards.h @@ -0,0 +1,38 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// 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 diff --git a/src/include/external/json/json.h b/src/include/external/json/json.h new file mode 100644 index 0000000..3d2798a --- /dev/null +++ b/src/include/external/json/json.h @@ -0,0 +1,15 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// 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_JSON_H_INCLUDED +#define JSON_JSON_H_INCLUDED + +#include "autolink.h" +#include "value.h" +#include "reader.h" +#include "writer.h" +#include "features.h" + +#endif // JSON_JSON_H_INCLUDED diff --git a/src/include/external/json/reader.h b/src/include/external/json/reader.h new file mode 100644 index 0000000..f367357 --- /dev/null +++ b/src/include/external/json/reader.h @@ -0,0 +1,420 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// 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) + +#pragma pack(push, 8) + +namespace Json +{ + +/** \brief Unserialize a JSON document into a + *Value. + * + * \deprecated Use CharReader and CharReaderBuilder. + */ +class JSONCPP_DEPRECATED("Use CharReader and CharReaderBuilder instead") JSON_API Reader +{ +public: + typedef char Char; + typedef const Char* Location; + + /** \brief An error tagged with where in the JSON text it was encountered. + * + * The offsets give the [start, limit) range of bytes within the text. Note + * that this is bytes, not codepoints. + * + */ + struct StructuredError + { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + JSONCPP_STRING message; + }; + + /** \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(JSONCPP_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.") + JSONCPP_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. + */ + JSONCPP_STRING getFormattedErrorMessages() const; + + /** \brief Returns a vector of structured erros encounted while parsing. + * \return A (possibly empty) vector of StructuredError objects. Currently + * only one error can be returned, but the caller should tolerate + * multiple + * errors. This can occur if the parser recovers from a non-fatal + * parse error and then encounters additional errors. + */ + std::vector getStructuredErrors() const; + + /** \brief Add a semantic error message. + * \param value JSON Value location associated with the error + * \param message The error message. + * \return \c true if the error was successfully added, \c false if the + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, const JSONCPP_STRING& message); + + /** \brief Add a semantic error message with extra context. + * \param value JSON Value location associated with the error + * \param message The error message. + * \param extra Additional JSON Value location to contextualize the error + * \return \c true if the error was successfully added, \c false if either + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra); + + /** \brief Return whether there are any errors. + * \return \c true if there are no errors to report \c false if + * errors have occurred. + */ + bool good() 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_; + JSONCPP_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, JSONCPP_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 JSONCPP_STRING& message, Token& token, Location extra = 0); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + JSONCPP_STRING getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + static bool containsNewLine(Location begin, Location end); + static JSONCPP_STRING normalizeEOL(Location begin, Location end); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + JSONCPP_STRING document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + JSONCPP_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, JSONCPP_STRING* errs) = 0; + + 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 CharReader* newCharReader() const = 0; + }; // Factory +}; // CharReader + +/** \brief Build a CharReader implementation. + +Usage: +\code + using namespace Json; + CharReaderBuilder builder; + builder["collectComments"] = false; + Value value; + JSONCPP_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(); + ~CharReaderBuilder() JSONCPP_OVERRIDE; + + CharReader* newCharReader() const JSONCPP_OVERRIDE; + + /** \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[](JSONCPP_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&, + JSONCPP_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 JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM&, Value&); + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // CPPTL_JSON_READER_H_INCLUDED diff --git a/src/include/external/json/value.h b/src/include/external/json/value.h new file mode 100644 index 0000000..d46b23d --- /dev/null +++ b/src/include/external/json/value.h @@ -0,0 +1,944 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// 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 + +//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 + +// 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) + +#pragma pack(push, 8) + +/** \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(JSONCPP_STRING const& msg); + ~Exception() JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; + char const* what() const JSONCPP_NOEXCEPT JSONCPP_OVERRIDE; +protected: + JSONCPP_STRING 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(JSONCPP_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(JSONCPP_STRING const& msg); +}; + +/// used internally +JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg); +/// used internally +JSONCPP_NORETURN void throwLogicError(JSONCPP_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& null; ///< We regret this reference to a global instance; prefer the simpler Value(). + static const Value& nullRef; ///< just a kludge for binary-compatibility; same as null + static Value const& nullSingleton(); ///< Prefer this to null or nullRef. + + /// 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); +#if JSON_HAS_RVALUE_REFERENCES + CZString(CZString&& other); +#endif + ~CZString(); + CZString& operator=(const CZString& other); + +#if JSON_HAS_RVALUE_REFERENCES + CZString& operator=(CZString&& other); +#endif + + 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 JSONCPP_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); +#if JSON_HAS_RVALUE_REFERENCES + /// Move constructor + Value(Value&& other); +#endif + ~Value(); + + /// Deep copy, then swap(other). + /// \note Over-write existing comments. To preserve comments, use #swapPayload(). + Value& operator=(Value other); + + /// Swap everything. + void swap(Value& other); + /// Swap values but leave comments and source offsets in place. + void swapPayload(Value& other); + + /// copy everything. + void copy(const Value& other); + /// copy values but leave comments and source offsets in place. + void copyPayload(const 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! +#if JSONCPP_USING_SECURE_MEMORY + unsigned getCStringLength() const; //Allows you to understand the length of the CString +#endif + JSONCPP_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); + +#if JSON_HAS_RVALUE_REFERENCES + Value& append(Value&& value); +#endif + + /// 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 JSONCPP_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 JSONCPP_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 JSONCPP_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 + JSONCPP_DEPRECATED("") + Value removeMember(const char* key); + /// Same as removeMember(const char*) + /// \param key may contain embedded nulls. + /// \deprecated + JSONCPP_DEPRECATED("") + Value removeMember(const JSONCPP_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(JSONCPP_STRING const& key, Value* removed); + /// Same as removeMember(JSONCPP_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 JSONCPP_STRING& key) const; + /// Same as isMember(JSONCPP_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(JSONCPP_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 JSONCPP_STRING& comment, CommentPlacement placement); + bool hasComment(CommentPlacement placement) const; + /// Include delimiters and embedded newlines. + JSONCPP_STRING getComment(CommentPlacement placement) const; + + JSONCPP_STRING toStyledString() const; + + const_iterator begin() const; + const_iterator end() const; + + iterator begin(); + iterator end(); + + // Accessors for the [start, limit) range of bytes within the JSON text from + // which this value was parsed, if any. + void setOffsetStart(ptrdiff_t start); + void setOffsetLimit(ptrdiff_t limit); + ptrdiff_t getOffsetStart() const; + ptrdiff_t getOffsetLimit() const; + +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_; + + // [start, limit) byte offsets in the source JSON text from which this Value + // was extracted. + ptrdiff_t start_; + ptrdiff_t limit_; +}; + +/** \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 JSONCPP_STRING& key); + +private: + enum Kind + { + kindNone = 0, + kindIndex, + kindKey + }; + JSONCPP_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 JSONCPP_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 JSONCPP_STRING& path, const InArgs& in); + void addPathInArg(const JSONCPP_STRING& path, + const InArgs& in, + InArgs::const_iterator& itInArg, + PathArgument::Kind kind); + void invalidPath(const JSONCPP_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. + JSONCPP_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(); + ValueConstIterator(ValueIterator const& other); + +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(); + explicit 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); +} +} + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // CPPTL_JSON_H_INCLUDED diff --git a/src/include/external/json/version.h b/src/include/external/json/version.h new file mode 100644 index 0000000..b1d2a5f --- /dev/null +++ b/src/include/external/json/version.h @@ -0,0 +1,20 @@ +// 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 "1.8.3" +# define JSONCPP_VERSION_MAJOR 1 +# define JSONCPP_VERSION_MINOR 8 +# define JSONCPP_VERSION_PATCH 3 +# define JSONCPP_VERSION_QUALIFIER +# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) + +#ifdef JSONCPP_USING_SECURE_MEMORY +#undef JSONCPP_USING_SECURE_MEMORY +#endif +#define JSONCPP_USING_SECURE_MEMORY 0 +// If non-zero, the library zeroes any memory that it has allocated before +// it frees its memory. + +#endif // JSON_VERSION_H_INCLUDED diff --git a/src/include/external/json/writer.h b/src/include/external/json/writer.h new file mode 100644 index 0000000..3360384 --- /dev/null +++ b/src/include/external/json/writer.h @@ -0,0 +1,345 @@ +// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors +// 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) + +#pragma pack(push, 8) + +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: + JSONCPP_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, JSONCPP_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. + */ +JSONCPP_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(); + ~StreamWriterBuilder() JSONCPP_OVERRIDE; + + /** + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + StreamWriter* newStreamWriter() const JSONCPP_OVERRIDE; + + /** \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[](JSONCPP_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 JSONCPP_DEPRECATED("Use StreamWriter instead") JSON_API Writer +{ +public: + virtual ~Writer(); + + virtual JSONCPP_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 JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API FastWriter : public Writer +{ + +public: + FastWriter(); + ~FastWriter() JSONCPP_OVERRIDE {} + + void enableYAMLCompatibility(); + + /** \brief 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. + */ + void dropNullPlaceholders(); + + void omitEndingLineFeed(); + +public: // overridden from Writer + JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; + +private: + void writeValue(const Value& value); + + JSONCPP_STRING document_; + bool yamlCompatiblityEnabled_; + bool dropNullPlaceholders_; + bool omitEndingLineFeed_; +}; + +/** \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 JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API StyledWriter : public Writer +{ +public: + StyledWriter(); + ~StyledWriter() JSONCPP_OVERRIDE {} + +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. + */ + JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultineArray(const Value& value); + void pushValue(const JSONCPP_STRING& value); + void writeIndent(); + void writeWithIndent(const JSONCPP_STRING& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + bool hasCommentForValue(const Value& value); + static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); + + typedef std::vector ChildValues; + + ChildValues childValues_; + JSONCPP_STRING document_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + unsigned 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. + * + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +class JSONCPP_DEPRECATED("Use StreamWriterBuilder instead") JSON_API StyledStreamWriter +{ +public: + /** + * \param indentation Each level will be indented by this amount extra. + */ + StyledStreamWriter(JSONCPP_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(JSONCPP_OSTREAM& out, const Value& root); + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultineArray(const Value& value); + void pushValue(const JSONCPP_STRING& value); + void writeIndent(); + void writeWithIndent(const JSONCPP_STRING& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + bool hasCommentForValue(const Value& value); + static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); + + typedef std::vector ChildValues; + + ChildValues childValues_; + JSONCPP_OSTREAM* document_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + JSONCPP_STRING indentation_; + bool addChildValues_ : 1; + bool indented_ : 1; +}; + +#if defined(JSON_HAS_INT64) +JSONCPP_STRING JSON_API valueToString(Int value); +JSONCPP_STRING JSON_API valueToString(UInt value); +#endif // if defined(JSON_HAS_INT64) +JSONCPP_STRING JSON_API valueToString(LargestInt value); +JSONCPP_STRING JSON_API valueToString(LargestUInt value); +JSONCPP_STRING JSON_API valueToString(double value); +JSONCPP_STRING JSON_API valueToString(bool value); +JSONCPP_STRING JSON_API valueToQuotedString(const char* value); + +/// \brief Output using the StyledStreamWriter. +/// \see Json::operator>>() +JSON_API JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM&, const Value& root); + +} // namespace Json + +#pragma pack(pop) + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // JSON_WRITER_H_INCLUDED diff --git a/src/include/external/plog/Appenders/AndroidAppender.h b/src/include/external/plog/Appenders/AndroidAppender.h new file mode 100644 index 0000000..7dc5f8c --- /dev/null +++ b/src/include/external/plog/Appenders/AndroidAppender.h @@ -0,0 +1,46 @@ +#pragma once +#include +#include + +namespace plog +{ +template +class AndroidAppender : public IAppender +{ +public: + AndroidAppender(const char* tag) : m_tag(tag) + { + } + + virtual void write(const Record& record) + { + std::string str = Formatter::format(record); + __android_log_print(toPriority(record.getSeverity()), m_tag, "%s", str.c_str()); + } + +private: + static android_LogPriority toPriority(Severity severity) + { + switch (severity) + { + case fatal: + return ANDROID_LOG_FATAL; + case error: + return ANDROID_LOG_ERROR; + case warning: + return ANDROID_LOG_WARN; + case info: + return ANDROID_LOG_INFO; + case debug: + return ANDROID_LOG_DEBUG; + case verbose: + return ANDROID_LOG_VERBOSE; + default: + return ANDROID_LOG_UNKNOWN; + } + } + +private: + const char* const m_tag; +}; +} diff --git a/src/include/external/plog/Appenders/ColorConsoleAppender.h b/src/include/external/plog/Appenders/ColorConsoleAppender.h new file mode 100644 index 0000000..b73763e --- /dev/null +++ b/src/include/external/plog/Appenders/ColorConsoleAppender.h @@ -0,0 +1,103 @@ +#pragma once +#include +#include + +namespace plog +{ +template +class ColorConsoleAppender : public ConsoleAppender +{ +public: +#ifdef _WIN32 + ColorConsoleAppender() : m_isatty(!!_isatty(_fileno(stdout))), m_stdoutHandle(), m_originalAttr() + { + if (m_isatty) + { + m_stdoutHandle = GetStdHandle(stdHandle::kOutput); + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo(m_stdoutHandle, &csbiInfo); + m_originalAttr = csbiInfo.wAttributes; + } + } +#else + ColorConsoleAppender() : m_isatty(!!::isatty(::fileno(stdout))) {} +#endif + +#ifdef __BORLANDC__ + static int _isatty(int fd) + { + return ::isatty(fd); + } +#endif + + virtual void write(const Record& record) + { + util::nstring str = Formatter::format(record); + util::MutexLock lock(this->m_mutex); + setColor(record.getSeverity()); + this->writestr(str); + resetColor(); + } + +private: + void setColor(Severity severity) + { + if (m_isatty) + { + switch (severity) + { +#ifdef _WIN32 + case fatal: + SetConsoleTextAttribute(m_stdoutHandle, foreground::kRed | foreground::kGreen | foreground::kBlue | foreground::kIntensity | background::kRed); // white on red background + break; + case error: + SetConsoleTextAttribute(m_stdoutHandle, static_cast(foreground::kRed | foreground::kIntensity | (m_originalAttr & 0xf0))); // red + break; + case warning: + SetConsoleTextAttribute(m_stdoutHandle, static_cast(foreground::kRed | foreground::kGreen | foreground::kIntensity | (m_originalAttr & 0xf0))); // yellow + break; + case debug: + case verbose: + SetConsoleTextAttribute(m_stdoutHandle, static_cast(foreground::kGreen | foreground::kBlue | foreground::kIntensity | (m_originalAttr & 0xf0))); // cyan + break; +#else + case fatal: + std::cout << "\x1B[97m\x1B[41m"; // white on red background + break; + case error: + std::cout << "\x1B[91m"; // red + break; + case warning: + std::cout << "\x1B[93m"; // yellow + break; + case debug: + case verbose: + std::cout << "\x1B[96m"; // cyan + break; +#endif + default: + break; + } + } + } + + void resetColor() + { + if (m_isatty) + { +#ifdef _WIN32 + SetConsoleTextAttribute(m_stdoutHandle, m_originalAttr); +#else + std::cout << "\x1B[0m\x1B[0K"; +#endif + } + } + +private: + bool m_isatty; +#ifdef _WIN32 + HANDLE m_stdoutHandle; + WORD m_originalAttr; +#endif +}; +} diff --git a/src/include/external/plog/Appenders/ConsoleAppender.h b/src/include/external/plog/Appenders/ConsoleAppender.h new file mode 100644 index 0000000..30c58ec --- /dev/null +++ b/src/include/external/plog/Appenders/ConsoleAppender.h @@ -0,0 +1,39 @@ +#pragma once +#include +#include +#include + +namespace plog +{ +template +class ConsoleAppender : public IAppender +{ +public: + ConsoleAppender() + { +#ifdef _WIN32 + ::setlocale(LC_ALL, ""); +#endif + } + + virtual void write(const Record& record) + { + util::nstring str = Formatter::format(record); + util::MutexLock lock(m_mutex); + writestr(str); + } + +protected: + void writestr(const util::nstring& str) + { +#ifdef _WIN32 + std::wcout << str << std::flush; +#else + std::cout << str << std::flush; +#endif + } + +protected: + util::Mutex m_mutex; +}; +} diff --git a/src/include/external/plog/Appenders/DebugOutputAppender.h b/src/include/external/plog/Appenders/DebugOutputAppender.h new file mode 100644 index 0000000..0c0d0d7 --- /dev/null +++ b/src/include/external/plog/Appenders/DebugOutputAppender.h @@ -0,0 +1,16 @@ +#pragma once +#include +#include + +namespace plog +{ +template +class DebugOutputAppender : public IAppender +{ +public: + virtual void write(const Record& record) + { + OutputDebugStringW(Formatter::format(record).c_str()); + } +}; +} diff --git a/src/include/external/plog/Appenders/EventLogAppender.h b/src/include/external/plog/Appenders/EventLogAppender.h new file mode 100644 index 0000000..61b5ea8 --- /dev/null +++ b/src/include/external/plog/Appenders/EventLogAppender.h @@ -0,0 +1,101 @@ +#pragma once +#include +#include + +namespace plog +{ +template +class EventLogAppender : public IAppender +{ +public: + EventLogAppender(const wchar_t* sourceName) : m_eventSource(RegisterEventSourceW(NULL, sourceName)) + { + } + + ~EventLogAppender() + { + DeregisterEventSource(m_eventSource); + } + + virtual void write(const Record& record) + { + std::wstring str = Formatter::format(record); + const wchar_t* logMessagePtr[] = { str.c_str() }; + ReportEventW(m_eventSource, logSeverityToType(record.getSeverity()), static_cast(record.getSeverity()), 0, NULL, 1, 0, logMessagePtr, NULL); + } + +private: + static WORD logSeverityToType(plog::Severity severity) + { + switch (severity) + { + case plog::fatal: + case plog::error: + return eventLog::kErrorType; + case plog::warning: + return eventLog::kWarningType; + case plog::info: + case plog::debug: + case plog::verbose: + default: + return eventLog::kInformationType; + } + } + +private: + HANDLE m_eventSource; +}; + +class EventLogAppenderRegistry +{ +public: + static bool add(const wchar_t* sourceName, const wchar_t* logName = L"Application") + { + std::wstring logKeyName; + std::wstring sourceKeyName; + getKeyNames(sourceName, logName, sourceKeyName, logKeyName); + HKEY sourceKey; + if (0 != RegCreateKeyExW(hkey::kLocalMachine, sourceKeyName.c_str(), 0, NULL, 0, regSam::kSetValue, NULL, &sourceKey, NULL)) + { + return false; + } + const DWORD kTypesSupported = eventLog::kErrorType | eventLog::kWarningType | eventLog::kInformationType; + RegSetValueExW(sourceKey, L"TypesSupported", 0, regType::kDword, &kTypesSupported, sizeof(kTypesSupported)); + const wchar_t kEventMessageFile[] = L"%windir%\\Microsoft.NET\\Framework\\v4.0.30319\\EventLogMessages.dll;%windir%\\Microsoft.NET\\Framework\\v2.0.50727\\EventLogMessages.dll"; + RegSetValueExW(sourceKey, L"EventMessageFile", 0, regType::kExpandSz, kEventMessageFile, static_cast(::wcslen(kEventMessageFile) * sizeof(wchar_t))); + RegCloseKey(sourceKey); + return true; + } + + static bool exists(const wchar_t* sourceName, const wchar_t* logName = L"Application") + { + std::wstring logKeyName; + std::wstring sourceKeyName; + getKeyNames(sourceName, logName, sourceKeyName, logKeyName); + HKEY sourceKey; + if (0 != RegOpenKeyExW(hkey::kLocalMachine, sourceKeyName.c_str(), 0, regSam::kQueryValue, &sourceKey)) + { + return false; + } + RegCloseKey(sourceKey); + return true; + } + + static void remove(const wchar_t* sourceName, const wchar_t* logName = L"Application") + { + std::wstring logKeyName; + std::wstring sourceKeyName; + getKeyNames(sourceName, logName, sourceKeyName, logKeyName); + RegDeleteKeyW(hkey::kLocalMachine, sourceKeyName.c_str()); + RegDeleteKeyW(hkey::kLocalMachine, logKeyName.c_str()); + } + +private: + static void getKeyNames(const wchar_t* sourceName, const wchar_t* logName, std::wstring& sourceKeyName, std::wstring& logKeyName) + { + const std::wstring kPrefix = L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\"; + logKeyName = kPrefix + logName; + sourceKeyName = logKeyName + L"\\" + sourceName; + } +}; +} diff --git a/src/include/external/plog/Appenders/IAppender.h b/src/include/external/plog/Appenders/IAppender.h new file mode 100644 index 0000000..1c5cf4c --- /dev/null +++ b/src/include/external/plog/Appenders/IAppender.h @@ -0,0 +1,15 @@ +#pragma once +#include + +namespace plog +{ +class IAppender +{ +public: + virtual ~IAppender() + { + } + + virtual void write(const Record& record) = 0; +}; +} diff --git a/src/include/external/plog/Appenders/RollingFileAppender.h b/src/include/external/plog/Appenders/RollingFileAppender.h new file mode 100644 index 0000000..f524368 --- /dev/null +++ b/src/include/external/plog/Appenders/RollingFileAppender.h @@ -0,0 +1,106 @@ +#pragma once +#include +#include +#include +#include + +namespace plog +{ +template +class RollingFileAppender : public IAppender +{ +public: + RollingFileAppender(const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0) + : m_fileSize() + , m_maxFileSize((std::max)(static_cast(maxFileSize), static_cast(1000))) // set a lower limit for the maxFileSize + , m_lastFileNumber((std::max)(maxFiles - 1, 0)) + , m_firstWrite(true) + { + util::splitFileName(fileName, m_fileNameNoExt, m_fileExt); + } + +#ifdef _WIN32 + RollingFileAppender(const char* fileName, size_t maxFileSize = 0, int maxFiles = 0) + : m_fileSize() + , m_maxFileSize((std::max)(static_cast(maxFileSize), static_cast(1000))) // set a lower limit for the maxFileSize + , m_lastFileNumber((std::max)(maxFiles - 1, 0)) + , m_firstWrite(true) + { + util::splitFileName(util::toWide(fileName).c_str(), m_fileNameNoExt, m_fileExt); + } +#endif + + virtual void write(const Record& record) + { + util::MutexLock lock(m_mutex); + if (m_firstWrite) + { + openLogFile(); + m_firstWrite = false; + } + else if (m_lastFileNumber > 0 && m_fileSize > m_maxFileSize && -1 != m_fileSize) + { + rollLogFiles(); + } + int bytesWritten = m_file.write(Converter::convert(Formatter::format(record))); + if (bytesWritten > 0) + { + m_fileSize += bytesWritten; + } + } + +private: + void rollLogFiles() + { + m_file.close(); + util::nstring lastFileName = buildFileName(m_lastFileNumber); + util::File::unlink(lastFileName.c_str()); + for (int fileNumber = m_lastFileNumber - 1; fileNumber >= 0; --fileNumber) + { + util::nstring currentFileName = buildFileName(fileNumber); + util::nstring nextFileName = buildFileName(fileNumber + 1); + util::File::rename(currentFileName.c_str(), nextFileName.c_str()); + } + openLogFile(); + } + + void openLogFile() + { + util::nstring fileName = buildFileName(); + m_fileSize = m_file.open(fileName.c_str()); + if (0 == m_fileSize) + { + int bytesWritten = m_file.write(Converter::header(Formatter::header())); + if (bytesWritten > 0) + { + m_fileSize += bytesWritten; + } + } + } + + util::nstring buildFileName(int fileNumber = 0) + { + util::nstringstream ss; + ss << m_fileNameNoExt; + if (fileNumber > 0) + { + ss << '.' << fileNumber; + } + if (!m_fileExt.empty()) + { + ss << '.' << m_fileExt; + } + return ss.str(); + } + +private: + util::Mutex m_mutex; + util::File m_file; + off_t m_fileSize; + const off_t m_maxFileSize; + const int m_lastFileNumber; + util::nstring m_fileExt; + util::nstring m_fileNameNoExt; + bool m_firstWrite; +}; +} diff --git a/src/include/external/plog/Converters/NativeEOLConverter.h b/src/include/external/plog/Converters/NativeEOLConverter.h new file mode 100644 index 0000000..61ac225 --- /dev/null +++ b/src/include/external/plog/Converters/NativeEOLConverter.h @@ -0,0 +1,40 @@ +#pragma once +#include +#include + +namespace plog +{ +template +class NativeEOLConverter : public NextConverter +{ +#ifdef WIN32 +public: + static std::string header(const util::nstring& str) + { + return NextConverter::header(fixLineEndings(str)); + } + + static std::string convert(const util::nstring& str) + { + return NextConverter::convert(fixLineEndings(str)); + } + +private: + static std::wstring fixLineEndings(const std::wstring& str) + { + std::wstring output; + output.reserve(str.length() * 2); + for (size_t i = 0; i < str.size(); ++i) + { + wchar_t ch = str[i]; + if (ch == L'\n') + { + output.push_back(L'\r'); + } + output.push_back(ch); + } + return output; + } +#endif +}; +} diff --git a/src/include/external/plog/Converters/UTF8Converter.h b/src/include/external/plog/Converters/UTF8Converter.h new file mode 100644 index 0000000..8441710 --- /dev/null +++ b/src/include/external/plog/Converters/UTF8Converter.h @@ -0,0 +1,27 @@ +#pragma once +#include + +namespace plog +{ +class UTF8Converter +{ +public: + static std::string header(const util::nstring& str) + { + const char kBOM[] = "\xEF\xBB\xBF"; + return std::string(kBOM) + convert(str); + } + +#ifdef WIN32 + static std::string convert(const util::nstring& str) + { + return util::toUTF8(str); + } +#else + static const std::string& convert(const util::nstring& str) + { + return str; + } +#endif +}; +} diff --git a/src/include/external/plog/Formatters/CsvFormatter.h b/src/include/external/plog/Formatters/CsvFormatter.h new file mode 100644 index 0000000..4137af6 --- /dev/null +++ b/src/include/external/plog/Formatters/CsvFormatter.h @@ -0,0 +1,46 @@ +#pragma once +#include +#include +#include + +namespace plog +{ +class CsvFormatter +{ +public: + static util::nstring header() + { + return PLOG_NSTR("Date;Time;Severity;TID;This;Function;Message\n"); + } + + static util::nstring format(const Record& record) + { + tm t; + util::localtime_s(&t, &record.getTime().time); + util::nstringstream ss; + ss << t.tm_year + 1900 << PLOG_NSTR("/") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_mon + 1 << PLOG_NSTR("/") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_mday << PLOG_NSTR(";"); + ss << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_hour << PLOG_NSTR(":") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_min << PLOG_NSTR(":") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_sec << PLOG_NSTR(".") << std::setfill(PLOG_NSTR('0')) << std::setw(3) << record.getTime().millitm << PLOG_NSTR(";"); + ss << severityToString(record.getSeverity()) << PLOG_NSTR(";"); + ss << record.getTid() << PLOG_NSTR(";"); + ss << record.getObject() << PLOG_NSTR(";"); + ss << record.getFunc() << PLOG_NSTR("@") << record.getLine() << PLOG_NSTR(";"); + util::nstring message = record.getMessage(); + if (message.size() > kMaxMessageSize) + { + message.resize(kMaxMessageSize); + message.append(PLOG_NSTR("...")); + } + util::nstringstream split(message); + util::nstring token; + while (!split.eof()) + { + std::getline(split, token, PLOG_NSTR('"')); + ss << PLOG_NSTR("\"") << token << PLOG_NSTR("\""); + } + ss << PLOG_NSTR("\n"); + return ss.str(); + } + + static const size_t kMaxMessageSize = 32000; +}; +} diff --git a/src/include/external/plog/Formatters/FuncMessageFormatter.h b/src/include/external/plog/Formatters/FuncMessageFormatter.h new file mode 100644 index 0000000..280c57d --- /dev/null +++ b/src/include/external/plog/Formatters/FuncMessageFormatter.h @@ -0,0 +1,22 @@ +#pragma once +#include +#include + +namespace plog +{ +class FuncMessageFormatter +{ +public: + static util::nstring header() + { + return util::nstring(); + } + + static util::nstring format(const Record& record) + { + util::nstringstream ss; + ss << record.getFunc() << PLOG_NSTR("@") << record.getLine() << PLOG_NSTR(": ") << record.getMessage() << PLOG_NSTR("\n"); + return ss.str(); + } +}; +} diff --git a/src/include/external/plog/Formatters/MessageOnlyFormatter.h b/src/include/external/plog/Formatters/MessageOnlyFormatter.h new file mode 100644 index 0000000..e56b1e8 --- /dev/null +++ b/src/include/external/plog/Formatters/MessageOnlyFormatter.h @@ -0,0 +1,22 @@ +#pragma once +#include +#include + +namespace plog +{ +class MessageOnlyFormatter +{ +public: + static util::nstring header() + { + return util::nstring(); + } + + static util::nstring format(const Record& record) + { + util::nstringstream ss; + ss << record.getMessage() << PLOG_NSTR("\n"); + return ss.str(); + } +}; +} diff --git a/src/include/external/plog/Formatters/TxtFormatter.h b/src/include/external/plog/Formatters/TxtFormatter.h new file mode 100644 index 0000000..ca07e30 --- /dev/null +++ b/src/include/external/plog/Formatters/TxtFormatter.h @@ -0,0 +1,30 @@ +#pragma once +#include +#include +#include + +namespace plog +{ +class TxtFormatter +{ +public: + static util::nstring header() + { + return util::nstring(); + } + + static util::nstring format(const Record& record) + { + tm t; + util::localtime_s(&t, &record.getTime().time); + util::nstringstream ss; + ss << t.tm_year + 1900 << "-" << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_mon + 1 << PLOG_NSTR("-") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_mday << PLOG_NSTR(" "); + ss << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_hour << PLOG_NSTR(":") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_min << PLOG_NSTR(":") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_sec << PLOG_NSTR(".") << std::setfill(PLOG_NSTR('0')) << std::setw(3) << record.getTime().millitm << PLOG_NSTR(" "); + ss << std::setfill(PLOG_NSTR(' ')) << std::setw(5) << std::left << severityToString(record.getSeverity()) << PLOG_NSTR(" "); + ss << PLOG_NSTR("[") << record.getTid() << PLOG_NSTR("] "); + ss << PLOG_NSTR("[") << record.getFunc() << PLOG_NSTR("@") << record.getLine() << PLOG_NSTR("] "); + ss << record.getMessage() << PLOG_NSTR("\n"); + return ss.str(); + } +}; +} diff --git a/src/include/external/plog/Init.h b/src/include/external/plog/Init.h new file mode 100644 index 0000000..2b46649 --- /dev/null +++ b/src/include/external/plog/Init.h @@ -0,0 +1,95 @@ +#pragma once +#include +#include +#include +#include +#include + +namespace plog +{ +namespace +{ +bool isCsv(const util::nchar* fileName) +{ + const util::nchar* dot = util::findExtensionDot(fileName); +#ifdef _WIN32 + return dot && 0 == std::wcscmp(dot, L".csv"); +#else + return dot && 0 == std::strcmp(dot, ".csv"); +#endif +} +} + +////////////////////////////////////////////////////////////////////////// +// Empty initializer / one appender + +template +inline Logger& init(Severity maxSeverity = none, IAppender* appender = NULL) +{ + static Logger logger(maxSeverity); + return appender ? logger.addAppender(appender) : logger; +} + +inline Logger& init(Severity maxSeverity = none, IAppender* appender = NULL) +{ + return init(maxSeverity, appender); +} + +////////////////////////////////////////////////////////////////////////// +// RollingFileAppender with any Formatter + +template +inline Logger& init(Severity maxSeverity, const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0) +{ + static RollingFileAppender rollingFileAppender(fileName, maxFileSize, maxFiles); + return init(maxSeverity, &rollingFileAppender); +} + +template +inline Logger& init(Severity maxSeverity, const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0) +{ + return init(maxSeverity, fileName, maxFileSize, maxFiles); +} + +////////////////////////////////////////////////////////////////////////// +// RollingFileAppender with TXT/CSV chosen by file extension + +template +inline Logger& init(Severity maxSeverity, const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0) +{ + return isCsv(fileName) ? init(maxSeverity, fileName, maxFileSize, maxFiles) : init(maxSeverity, fileName, maxFileSize, maxFiles); +} + +inline Logger& init(Severity maxSeverity, const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0) +{ + return init(maxSeverity, fileName, maxFileSize, maxFiles); +} + +////////////////////////////////////////////////////////////////////////// +// CHAR variants for Windows + +#ifdef _WIN32 +template +inline Logger& init(Severity maxSeverity, const char* fileName, size_t maxFileSize = 0, int maxFiles = 0) +{ + return init(maxSeverity, util::toWide(fileName).c_str(), maxFileSize, maxFiles); +} + +template +inline Logger& init(Severity maxSeverity, const char* fileName, size_t maxFileSize = 0, int maxFiles = 0) +{ + return init(maxSeverity, fileName, maxFileSize, maxFiles); +} + +template +inline Logger& init(Severity maxSeverity, const char* fileName, size_t maxFileSize = 0, int maxFiles = 0) +{ + return init(maxSeverity, util::toWide(fileName).c_str(), maxFileSize, maxFiles); +} + +inline Logger& init(Severity maxSeverity, const char* fileName, size_t maxFileSize = 0, int maxFiles = 0) +{ + return init(maxSeverity, fileName, maxFileSize, maxFiles); +} +#endif +} diff --git a/src/include/external/plog/Log.h b/src/include/external/plog/Log.h new file mode 100644 index 0000000..5144482 --- /dev/null +++ b/src/include/external/plog/Log.h @@ -0,0 +1,105 @@ +////////////////////////////////////////////////////////////////////////// +// Plog - portable and simple log for C++ +// Documentation and sources: https://github.com/SergiusTheBest/plog +// License: MPL 2.0, http://mozilla.org/MPL/2.0/ + +#pragma once +#include +#include + +////////////////////////////////////////////////////////////////////////// +// Helper macros that get context info + +#if _MSC_VER >= 1600 && !defined(__INTELLISENSE__) // >= Visual Studio 2010 and skip IntelliSense +# define PLOG_GET_THIS() __if_exists(this) { this } __if_not_exists(this) { 0 } +#else +# define PLOG_GET_THIS() 0 +#endif + +#ifdef _MSC_VER +# define PLOG_GET_FUNC() __FUNCTION__ +#elif defined(__BORLANDC__) +# define PLOG_GET_FUNC() __FUNC__ +#else +# define PLOG_GET_FUNC() __PRETTY_FUNCTION__ +#endif + +#if PLOG_CAPTURE_FILE +# define PLOG_GET_FILE() __FILE__ +#else +# define PLOG_GET_FILE() "" +#endif + +////////////////////////////////////////////////////////////////////////// +// Log severity level checker + +#define IF_LOG_(instance, severity) !(plog::get() && plog::get()->checkSeverity(severity)) ? (void)0 : +#define IF_LOG(severity) IF_LOG_(PLOG_DEFAULT_INSTANCE, severity) + +////////////////////////////////////////////////////////////////////////// +// Main logging macros + +#define LOG_(instance, severity) IF_LOG_(instance, severity) (*plog::get()) += plog::Record(severity, PLOG_GET_FUNC(), __LINE__, PLOG_GET_FILE(), PLOG_GET_THIS()) +#define LOG(severity) LOG_(PLOG_DEFAULT_INSTANCE, severity) + +#define LOG_VERBOSE LOG(plog::verbose) +#define LOG_DEBUG LOG(plog::debug) +#define LOG_INFO LOG(plog::info) +#define LOG_WARNING LOG(plog::warning) +#define LOG_ERROR LOG(plog::error) +#define LOG_FATAL LOG(plog::fatal) + +#define LOG_VERBOSE_(instance) LOG_(instance, plog::verbose) +#define LOG_DEBUG_(instance) LOG_(instance, plog::debug) +#define LOG_INFO_(instance) LOG_(instance, plog::info) +#define LOG_WARNING_(instance) LOG_(instance, plog::warning) +#define LOG_ERROR_(instance) LOG_(instance, plog::error) +#define LOG_FATAL_(instance) LOG_(instance, plog::fatal) + +#define LOGV LOG_VERBOSE +#define LOGD LOG_DEBUG +#define LOGI LOG_INFO +#define LOGW LOG_WARNING +#define LOGE LOG_ERROR +#define LOGF LOG_FATAL + +#define LOGV_(instance) LOG_VERBOSE_(instance) +#define LOGD_(instance) LOG_DEBUG_(instance) +#define LOGI_(instance) LOG_INFO_(instance) +#define LOGW_(instance) LOG_WARNING_(instance) +#define LOGE_(instance) LOG_ERROR_(instance) +#define LOGF_(instance) LOG_FATAL_(instance) + +////////////////////////////////////////////////////////////////////////// +// Conditional logging macros + +#define LOG_IF_(instance, severity, condition) !(condition) ? void(0) : LOG_(instance, severity) +#define LOG_IF(severity, condition) LOG_IF_(PLOG_DEFAULT_INSTANCE, severity, condition) + +#define LOG_VERBOSE_IF(condition) LOG_IF(plog::verbose, condition) +#define LOG_DEBUG_IF(condition) LOG_IF(plog::debug, condition) +#define LOG_INFO_IF(condition) LOG_IF(plog::info, condition) +#define LOG_WARNING_IF(condition) LOG_IF(plog::warning, condition) +#define LOG_ERROR_IF(condition) LOG_IF(plog::error, condition) +#define LOG_FATAL_IF(condition) LOG_IF(plog::fatal, condition) + +#define LOG_VERBOSE_IF_(instance, condition) LOG_IF_(instance, plog::verbose, condition) +#define LOG_DEBUG_IF_(instance, condition) LOG_IF_(instance, plog::debug, condition) +#define LOG_INFO_IF_(instance, condition) LOG_IF_(instance, plog::info, condition) +#define LOG_WARNING_IF_(instance, condition) LOG_IF_(instance, plog::warning, condition) +#define LOG_ERROR_IF_(instance, condition) LOG_IF_(instance, plog::error, condition) +#define LOG_FATAL_IF_(instance, condition) LOG_IF_(instance, plog::fatal, condition) + +#define LOGV_IF(condition) LOG_VERBOSE_IF(condition) +#define LOGD_IF(condition) LOG_DEBUG_IF(condition) +#define LOGI_IF(condition) LOG_INFO_IF(condition) +#define LOGW_IF(condition) LOG_WARNING_IF(condition) +#define LOGE_IF(condition) LOG_ERROR_IF(condition) +#define LOGF_IF(condition) LOG_FATAL_IF(condition) + +#define LOGV_IF_(instance, condition) LOG_VERBOSE_IF_(instance, condition) +#define LOGD_IF_(instance, condition) LOG_DEBUG_IF_(instance, condition) +#define LOGI_IF_(instance, condition) LOG_INFO_IF_(instance, condition) +#define LOGW_IF_(instance, condition) LOG_WARNING_IF_(instance, condition) +#define LOGE_IF_(instance, condition) LOG_ERROR_IF_(instance, condition) +#define LOGF_IF_(instance, condition) LOG_FATAL_IF_(instance, condition) diff --git a/src/include/external/plog/Logger.h b/src/include/external/plog/Logger.h new file mode 100644 index 0000000..414d0ec --- /dev/null +++ b/src/include/external/plog/Logger.h @@ -0,0 +1,73 @@ +#pragma once +#include +#include +#include + +#ifndef PLOG_DEFAULT_INSTANCE +# define PLOG_DEFAULT_INSTANCE 0 +#endif + +namespace plog +{ +template +class Logger : public util::Singleton >, public IAppender +{ +public: + Logger(Severity maxSeverity = none) : m_maxSeverity(maxSeverity) + { + } + + Logger& addAppender(IAppender* appender) + { + assert(appender != this); + m_appenders.push_back(appender); + return *this; + } + + Severity getMaxSeverity() const + { + return m_maxSeverity; + } + + void setMaxSeverity(Severity severity) + { + m_maxSeverity = severity; + } + + bool checkSeverity(Severity severity) const + { + return severity <= m_maxSeverity; + } + + virtual void write(const Record& record) + { + if (checkSeverity(record.getSeverity())) + { + *this += record; + } + } + + void operator+=(const Record& record) + { + for (std::vector::iterator it = m_appenders.begin(); it != m_appenders.end(); ++it) + { + (*it)->write(record); + } + } + +private: + Severity m_maxSeverity; + std::vector m_appenders; +}; + +template +inline Logger* get() +{ + return Logger::getInstance(); +} + +inline Logger* get() +{ + return Logger::getInstance(); +} +} diff --git a/src/include/external/plog/Record.h b/src/include/external/plog/Record.h new file mode 100644 index 0000000..0df9b43 --- /dev/null +++ b/src/include/external/plog/Record.h @@ -0,0 +1,159 @@ +#pragma once +#include +#include + +namespace plog +{ +namespace detail +{ +////////////////////////////////////////////////////////////////////////// +// Stream output operators as free functions + +inline void operator<<(util::nstringstream& stream, const char* data) +{ + data = data ? data : "(null)"; +#if defined(_WIN32) && defined(__BORLANDC__) + stream << util::toWide(data); +#elif defined(_WIN32) + std::operator<<(stream, util::toWide(data)); +#else + std::operator<<(stream, data); +#endif +} + +inline void operator<<(util::nstringstream& stream, const std::string& data) +{ + plog::detail::operator<<(stream, data.c_str()); +} + +#ifndef __ANDROID__ +inline void operator<<(util::nstringstream& stream, const wchar_t* data) +{ + data = data ? data : L"(null)"; +#ifdef _WIN32 + std::operator<<(stream, data); +#else + std::operator<<(stream, util::toNarrow(data)); +#endif +} + +inline void operator<<(util::nstringstream& stream, const std::wstring& data) +{ + plog::detail::operator<<(stream, data.c_str()); +} +#endif +} + +class Record +{ +public: + Record(Severity severity, const char* func, size_t line, const char* file, const void* object) + : m_severity(severity), m_tid(util::gettid()), m_object(object), m_line(line), m_func(func), m_file(file) + { + util::ftime(&m_time); + } + + ////////////////////////////////////////////////////////////////////////// + // Stream output operators + + Record& operator<<(char data) + { + char str[] = { data, 0 }; + return *this << str; + } + +#ifndef __ANDROID__ + Record& operator<<(wchar_t data) + { + wchar_t str[] = { data, 0 }; + return *this << str; + } +#endif + +#ifdef _WIN32 + Record& operator<<(std::wostream& (*data)(std::wostream&)) +#else + Record& operator<<(std::ostream& (*data)(std::ostream&)) +#endif + { + m_message << data; + return *this; + } + +#ifdef QT_VERSION + Record& operator<<(const QString& data) + { +#ifdef _WIN32 + return *this << data.toStdWString(); +#else + return *this << data.toStdString(); +#endif + } +#endif + + template + Record& operator<<(const T& data) + { + using namespace plog::detail; + m_message << data; + return *this; + } + + ////////////////////////////////////////////////////////////////////////// + // Getters + + virtual const util::Time& getTime() const + { + return m_time; + } + + virtual Severity getSeverity() const + { + return m_severity; + } + + virtual unsigned int getTid() const + { + return m_tid; + } + + virtual const void* getObject() const + { + return m_object; + } + + virtual size_t getLine() const + { + return m_line; + } + + virtual const util::nchar* getMessage() const + { + m_messageStr = m_message.str(); + return m_messageStr.c_str(); + } + + virtual const char* getFunc() const + { + m_funcStr = util::processFuncName(m_func); + return m_funcStr.c_str(); + } + + virtual const char* getFile() const + { + return m_file; + } + +private: + util::Time m_time; + const Severity m_severity; + const unsigned int m_tid; + const void* const m_object; + const size_t m_line; + util::nstringstream m_message; + const char* const m_func; + const char* const m_file; + mutable std::string m_funcStr; + mutable util::nstring m_messageStr; +}; +} diff --git a/src/include/external/plog/Severity.h b/src/include/external/plog/Severity.h new file mode 100644 index 0000000..bdbc317 --- /dev/null +++ b/src/include/external/plog/Severity.h @@ -0,0 +1,48 @@ +#pragma once + +namespace plog +{ +enum Severity +{ + none = 0, + fatal = 1, + error = 2, + warning = 3, + info = 4, + debug = 5, + verbose = 6 +}; + +inline const char *severityToString(Severity severity) +{ + switch (severity) + { + case fatal: + return "FATAL"; + case error: + return "ERROR"; + case warning: + return "WARN"; + case info: + return "INFO"; + case debug: + return "DEBUG"; + case verbose: + return "VERB"; + default: + return "NONE"; + } +} + +inline Severity severityFromString(const char *str) +{ + for (Severity severity = fatal; severity <= verbose; severity = static_cast(severity + 1)) + { + if (severityToString(severity)[0] == str[0]) + { + return severity; + } + } + return none; +} +} diff --git a/src/include/external/plog/Util.h b/src/include/external/plog/Util.h new file mode 100644 index 0000000..c27142f --- /dev/null +++ b/src/include/external/plog/Util.h @@ -0,0 +1,382 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +# include +# include +# include +# include +# include +#else +# include +# include +# include +# include +# ifndef __ANDROID__ +# include +# endif +#endif + +#ifdef _WIN32 +# define _PLOG_NSTR(x) L##x +# define PLOG_NSTR(x) _PLOG_NSTR(x) +#else +# define PLOG_NSTR(x) x +#endif + +namespace plog +{ +namespace util +{ +#ifdef _WIN32 +typedef std::wstring nstring; +typedef std::wstringstream nstringstream; +typedef wchar_t nchar; +#else +typedef std::string nstring; +typedef std::stringstream nstringstream; +typedef char nchar; +#endif + +inline void localtime_s(struct tm* t, const time_t* time) +{ +#if defined(_WIN32) && defined(__BORLANDC__) + ::localtime_s(time, t); +#elif defined(_WIN32) && defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) + *t = *::localtime(time); +#elif defined(_WIN32) + ::localtime_s(t, time); +#else + ::localtime_r(time, t); +#endif +} + +#ifdef _WIN32 +typedef timeb Time; + +inline void ftime(Time* t) +{ + ::ftime(t); +} +#else +struct Time +{ + time_t time; + unsigned short millitm; +}; + +inline void ftime(Time* t) +{ + timeval tv; + ::gettimeofday(&tv, NULL); + t->time = tv.tv_sec; + t->millitm = static_cast(tv.tv_usec / 1000); +} +#endif + +inline unsigned int gettid() +{ +#ifdef _WIN32 + return GetCurrentThreadId(); +#elif defined(__unix__) + return static_cast(::syscall(__NR_gettid)); +#elif defined(__APPLE__) + uint64_t tid64; + pthread_threadid_np(NULL, &tid64); + return static_cast(tid64); +#endif +} + +#if !defined(__ANDROID__) && !defined(_WIN32) +inline std::string toNarrow(const wchar_t* wstr) +{ + size_t wlen = ::wcslen(wstr); + std::string str(wlen * sizeof(wchar_t), 0); + if (!str.empty()) + { + const char* in = reinterpret_cast(&wstr[0]); + char* out = &str[0]; + size_t inBytes = wlen * sizeof(wchar_t); + size_t outBytes = str.size(); + iconv_t cd = ::iconv_open("UTF-8", "WCHAR_T"); + ::iconv(cd, const_cast(&in), &inBytes, &out, &outBytes); + ::iconv_close(cd); + str.resize(str.size() - outBytes); + } + return str; +} +#endif + +#ifdef _WIN32 +inline std::wstring toWide(const char* str) +{ + size_t len = ::strlen(str); + std::wstring wstr(len, 0); + if (!wstr.empty()) + { + int wlen = MultiByteToWideChar(codePage::kActive, 0, str, static_cast(len), &wstr[0], static_cast(wstr.size())); + wstr.resize(wlen); + } + return wstr; +} + +inline std::string toUTF8(const std::wstring& wstr) +{ + std::string str(wstr.size() * sizeof(wchar_t), 0); + if (!str.empty()) + { + int len = WideCharToMultiByte(codePage::kUTF8, 0, wstr.c_str(), static_cast(wstr.size()), &str[0], static_cast(str.size()), 0, 0); + str.resize(len); + } + return str; +} +#endif + +inline std::string processFuncName(const char* func) +{ +#if (defined(_WIN32) && !defined(__MINGW32__)) || defined(__OBJC__) + return std::string(func); +#else + const char* funcBegin = func; + const char* funcEnd = ::strchr(funcBegin, '('); + if (!funcEnd) + { + return std::string(func); + } + for (const char* i = funcEnd - 1; i >= funcBegin; --i) // search backwards for the first space char + { + if (*i == ' ') + { + funcBegin = i + 1; + break; + } + } + return std::string(funcBegin, funcEnd); +#endif +} + +inline const nchar* findExtensionDot(const nchar* fileName) +{ +#ifdef _WIN32 + return std::wcsrchr(fileName, L'.'); +#else + return std::strrchr(fileName, '.'); +#endif +} + +inline void splitFileName(const nchar* fileName, nstring& fileNameNoExt, nstring& fileExt) +{ + const nchar* dot = findExtensionDot(fileName); + if (dot) + { + fileNameNoExt.assign(fileName, dot); + fileExt.assign(dot + 1); + } + else + { + fileNameNoExt.assign(fileName); + fileExt.clear(); + } +} + +class NonCopyable +{ +protected: + NonCopyable() + { + } + +private: + NonCopyable(const NonCopyable&); + NonCopyable& operator=(const NonCopyable&); +}; + +class File : NonCopyable +{ +public: + File() : m_file(-1) + { + } + + File(const nchar* fileName) : m_file(-1) + { + open(fileName); + } + + ~File() + { + close(); + } + + off_t open(const nchar* fileName) + { +#if defined(_WIN32) && (defined(__BORLANDC__) || defined(__MINGW32__)) + m_file = ::_wsopen(fileName, _O_CREAT | _O_WRONLY | _O_BINARY, SH_DENYWR, _S_IREAD | _S_IWRITE); +#elif defined(_WIN32) + ::_wsopen_s(&m_file, fileName, _O_CREAT | _O_WRONLY | _O_BINARY, _SH_DENYWR, _S_IREAD | _S_IWRITE); +#else + m_file = ::open(fileName, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +#endif + return seek(0, SEEK_END); + } + + int write(const void* buf, size_t count) + { +#ifdef _WIN32 + return m_file != -1 ? ::_write(m_file, buf, static_cast(count)) : -1; +#else + return m_file != -1 ? static_cast(::write(m_file, buf, count)) : -1; +#endif + } + + template + int write(const std::basic_string& str) + { + return write(str.data(), str.size() * sizeof(CharType)); + } + + off_t seek(off_t offset, int whence) + { +#ifdef _WIN32 + return m_file != -1 ? ::_lseek(m_file, offset, whence) : -1; +#else + return m_file != -1 ? ::lseek(m_file, offset, whence) : -1; +#endif + } + + void close() + { + if (m_file != -1) + { +#ifdef _WIN32 + ::_close(m_file); +#else + ::close(m_file); +#endif + m_file = -1; + } + } + + static int unlink(const nchar* fileName) + { +#ifdef _WIN32 + return ::_wunlink(fileName); +#else + return ::unlink(fileName); +#endif + } + + static int rename(const nchar* oldFilename, const nchar* newFilename) + { +#ifdef _WIN32 + return MoveFileW(oldFilename, newFilename); +#else + return ::rename(oldFilename, newFilename); +#endif + } + +private: + int m_file; +}; + +class Mutex : NonCopyable +{ +public: + Mutex() + { +#ifdef _WIN32 + InitializeCriticalSection(&m_sync); +#else + ::pthread_mutex_init(&m_sync, 0); +#endif + } + + ~Mutex() + { +#ifdef _WIN32 + DeleteCriticalSection(&m_sync); +#else + ::pthread_mutex_destroy(&m_sync); +#endif + } + + friend class MutexLock; + +private: + void lock() + { +#ifdef _WIN32 + EnterCriticalSection(&m_sync); +#else + ::pthread_mutex_lock(&m_sync); +#endif + } + + void unlock() + { +#ifdef _WIN32 + LeaveCriticalSection(&m_sync); +#else + ::pthread_mutex_unlock(&m_sync); +#endif + } + +private: +#ifdef _WIN32 + CRITICAL_SECTION m_sync; +#else + pthread_mutex_t m_sync; +#endif +}; + +class MutexLock : NonCopyable +{ +public: + MutexLock(Mutex& mutex) : m_mutex(mutex) + { + m_mutex.lock(); + } + + ~MutexLock() + { + m_mutex.unlock(); + } + +private: + Mutex& m_mutex; +}; + +template +class Singleton : NonCopyable +{ +public: + Singleton() + { + assert(!m_instance); + m_instance = static_cast(this); + } + + ~Singleton() + { + assert(m_instance); + m_instance = 0; + } + + static T* getInstance() + { + return m_instance; + } + +private: + static T* m_instance; +}; + +template +T* Singleton::m_instance = NULL; +} +} diff --git a/src/include/external/plog/WinApi.h b/src/include/external/plog/WinApi.h new file mode 100644 index 0000000..b33d256 --- /dev/null +++ b/src/include/external/plog/WinApi.h @@ -0,0 +1,135 @@ +#pragma once + +#ifdef _WIN32 +namespace plog +{ +typedef unsigned long DWORD; +typedef unsigned short WORD; +typedef unsigned int UINT; +typedef int BOOL; +typedef long LSTATUS; +typedef char* LPSTR; +typedef wchar_t* LPWSTR; +typedef const char* LPCSTR; +typedef const wchar_t* LPCWSTR; +typedef void* HANDLE; +typedef void* HKEY; +typedef size_t ULONG_PTR; + +struct CRITICAL_SECTION +{ + void* DebugInfo; + long LockCount; + long RecursionCount; + HANDLE OwningThread; + HANDLE LockSemaphore; + ULONG_PTR SpinCount; +}; + +struct COORD +{ + short X; + short Y; +}; + +struct SMALL_RECT +{ + short Left; + short Top; + short Right; + short Bottom; +}; + +struct CONSOLE_SCREEN_BUFFER_INFO +{ + COORD dwSize; + COORD dwCursorPosition; + WORD wAttributes; + SMALL_RECT srWindow; + COORD dwMaximumWindowSize; +}; + +namespace codePage +{ +const UINT kActive = 0; +const UINT kUTF8 = 65001; +} + +namespace eventLog +{ +const WORD kErrorType = 0x0001; +const WORD kWarningType = 0x0002; +const WORD kInformationType = 0x0004; +} + +namespace hkey +{ +const HKEY kLocalMachine = reinterpret_cast(static_cast(0x80000002)); +} + +namespace regSam +{ +const DWORD kQueryValue = 0x0001; +const DWORD kSetValue = 0x0002; +} + +namespace regType +{ +const DWORD kExpandSz = 2; +const DWORD kDword = 4; +} + +namespace stdHandle +{ +const DWORD kOutput = static_cast(-11); +} + +namespace foreground +{ +const WORD kBlue = 0x0001; +const WORD kGreen = 0x0002; +const WORD kRed = 0x0004; +const WORD kIntensity = 0x0008; +} + +namespace background +{ +const WORD kBlue = 0x0010; +const WORD kGreen = 0x0020; +const WORD kRed = 0x0040; +const WORD kIntensity = 0x0080; +} + +extern "C" +{ + __declspec(dllimport) int __stdcall MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar); + __declspec(dllimport) int __stdcall WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, const char* lpDefaultChar, BOOL* lpUsedDefaultChar); + + __declspec(dllimport) DWORD __stdcall GetCurrentThreadId(); + + __declspec(dllimport) BOOL __stdcall MoveFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName); + + __declspec(dllimport) void __stdcall InitializeCriticalSection(CRITICAL_SECTION* lpCriticalSection); + __declspec(dllimport) void __stdcall EnterCriticalSection(CRITICAL_SECTION* lpCriticalSection); + __declspec(dllimport) void __stdcall LeaveCriticalSection(CRITICAL_SECTION* lpCriticalSection); + __declspec(dllimport) void __stdcall DeleteCriticalSection(CRITICAL_SECTION* lpCriticalSection); + + __declspec(dllimport) HANDLE __stdcall RegisterEventSourceW(LPCWSTR lpUNCServerName, LPCWSTR lpSourceName); + __declspec(dllimport) BOOL __stdcall DeregisterEventSource(HANDLE hEventLog); + __declspec(dllimport) BOOL __stdcall ReportEventW(HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, void* lpUserSid, WORD wNumStrings, DWORD dwDataSize, LPCWSTR* lpStrings, void* lpRawData); + + __declspec(dllimport) LSTATUS __stdcall RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions, DWORD samDesired, void* lpSecurityAttributes, HKEY* phkResult, DWORD* lpdwDisposition); + __declspec(dllimport) LSTATUS __stdcall RegSetValueExW(HKEY hKey, LPCWSTR lpValueName, DWORD Reserved, DWORD dwType, const void* lpData, DWORD cbData); + __declspec(dllimport) LSTATUS __stdcall RegCloseKey(HKEY hKey); + __declspec(dllimport) LSTATUS __stdcall RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, DWORD samDesired, HKEY* phkResult); + __declspec(dllimport) LSTATUS __stdcall RegDeleteKeyW(HKEY hKey, LPCWSTR lpSubKey); + + __declspec(dllimport) HANDLE __stdcall GetStdHandle(DWORD nStdHandle); + + __declspec(dllimport) BOOL __stdcall GetConsoleScreenBufferInfo(HANDLE hConsoleOutput, CONSOLE_SCREEN_BUFFER_INFO* lpConsoleScreenBufferInfo); + __declspec(dllimport) BOOL __stdcall SetConsoleTextAttribute(HANDLE hConsoleOutput, WORD wAttributes); + + __declspec(dllimport) void __stdcall OutputDebugStringW(LPCWSTR lpOutputString); +} +} +#endif // _WIN32 diff --git a/src/include/external/yaml/config.h b/src/include/external/yaml/config.h new file mode 100644 index 0000000..00d0d66 --- /dev/null +++ b/src/include/external/yaml/config.h @@ -0,0 +1,80 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* Name of package */ +#define PACKAGE "yaml" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "https://github.com/yaml/libyaml/issues/new" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "yaml" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "yaml 0.1.7" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "yaml" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.1.7" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "0.1.7" + +/* Define the major version number. */ +#define YAML_VERSION_MAJOR 0 + +/* Define the minor version number. */ +#define YAML_VERSION_MINOR 1 + +/* Define the patch version number. */ +#define YAML_VERSION_PATCH 7 + +/* Define the version string. */ +#define YAML_VERSION_STRING "0.1.7" + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ diff --git a/src/include/external/yaml/yaml.h b/src/include/external/yaml/yaml.h new file mode 100644 index 0000000..7db4dda --- /dev/null +++ b/src/include/external/yaml/yaml.h @@ -0,0 +1,2042 @@ +/** + * @file yaml.h + * @brief Public interface for libyaml. + * + * Include the header file with the code: + * @code + * #include + * @endcode + */ + +#ifndef YAML_H +#define YAML_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/** + * @defgroup export Export Definitions + * @{ + */ + +/** The public API declaration. */ + +#ifdef _WIN32 +# if defined(YAML_DECLARE_STATIC) +# define YAML_DECLARE(type) type +# elif defined(YAML_DECLARE_EXPORT) +# define YAML_DECLARE(type) __declspec(dllexport) type +# else +# define YAML_DECLARE(type) __declspec(dllimport) type +# endif +#else +# define YAML_DECLARE(type) type +#endif + +/** @} */ + +/** + * @defgroup version Version Information + * @{ + */ + +/** + * Get the library version as a string. + * + * @returns The function returns the pointer to a static string of the form + * @c "X.Y.Z", where @c X is the major version number, @c Y is a minor version + * number, and @c Z is the patch version number. + */ + +YAML_DECLARE(const char *) +yaml_get_version_string(void); + +/** + * Get the library version numbers. + * + * @param[out] major Major version number. + * @param[out] minor Minor version number. + * @param[out] patch Patch version number. + */ + +YAML_DECLARE(void) +yaml_get_version(int *major, int *minor, int *patch); + +/** @} */ + +/** + * @defgroup basic Basic Types + * @{ + */ + +/** The character type (UTF-8 octet). */ +typedef unsigned char yaml_char_t; + +/** The version directive data. */ +typedef struct yaml_version_directive_s +{ + /** The major version number. */ + int major; + /** The minor version number. */ + int minor; +} yaml_version_directive_t; + +/** The tag directive data. */ +typedef struct yaml_tag_directive_s +{ + /** The tag handle. */ + yaml_char_t *handle; + /** The tag prefix. */ + yaml_char_t *prefix; +} yaml_tag_directive_t; + +/** The stream encoding. */ +typedef enum yaml_encoding_e +{ + /** Let the parser choose the encoding. */ + YAML_ANY_ENCODING, + /** The default UTF-8 encoding. */ + YAML_UTF8_ENCODING, + /** The UTF-16-LE encoding with BOM. */ + YAML_UTF16LE_ENCODING, + /** The UTF-16-BE encoding with BOM. */ + YAML_UTF16BE_ENCODING +} yaml_encoding_t; + +/** Line break types. */ + +typedef enum yaml_break_e +{ + /** Let the parser choose the break type. */ + YAML_ANY_BREAK, + /** Use CR for line breaks (Mac style). */ + YAML_CR_BREAK, + /** Use LN for line breaks (Unix style). */ + YAML_LN_BREAK, + /** Use CR LN for line breaks (DOS style). */ + YAML_CRLN_BREAK +} yaml_break_t; + +/** Many bad things could happen with the parser and emitter. */ +typedef enum yaml_error_type_e +{ + /** No error is produced. */ + YAML_NO_ERROR, + + /** Cannot allocate or reallocate a block of memory. */ + YAML_MEMORY_ERROR, + + /** Cannot read or decode the input stream. */ + YAML_READER_ERROR, + /** Cannot scan the input stream. */ + YAML_SCANNER_ERROR, + /** Cannot parse the input stream. */ + YAML_PARSER_ERROR, + /** Cannot compose a YAML document. */ + YAML_COMPOSER_ERROR, + + /** Cannot write to the output stream. */ + YAML_WRITER_ERROR, + /** Cannot emit a YAML stream. */ + YAML_EMITTER_ERROR +} yaml_error_type_t; + +/** The pointer position. */ +typedef struct yaml_mark_s +{ + /** The position index. */ + size_t index; + + /** The position line. */ + size_t line; + + /** The position column. */ + size_t column; +} yaml_mark_t; + +/** @} */ + +/** + * @defgroup styles Node Styles + * @{ + */ + +/** Scalar styles. */ +typedef enum yaml_scalar_style_e +{ + /** Let the emitter choose the style. */ + YAML_ANY_SCALAR_STYLE, + + /** The plain scalar style. */ + YAML_PLAIN_SCALAR_STYLE, + + /** The single-quoted scalar style. */ + YAML_SINGLE_QUOTED_SCALAR_STYLE, + /** The double-quoted scalar style. */ + YAML_DOUBLE_QUOTED_SCALAR_STYLE, + + /** The literal scalar style. */ + YAML_LITERAL_SCALAR_STYLE, + /** The folded scalar style. */ + YAML_FOLDED_SCALAR_STYLE +} yaml_scalar_style_t; + +/** Sequence styles. */ +typedef enum yaml_sequence_style_e +{ + /** Let the emitter choose the style. */ + YAML_ANY_SEQUENCE_STYLE, + + /** The block sequence style. */ + YAML_BLOCK_SEQUENCE_STYLE, + /** The flow sequence style. */ + YAML_FLOW_SEQUENCE_STYLE +} yaml_sequence_style_t; + +/** Mapping styles. */ +typedef enum yaml_mapping_style_e +{ + /** Let the emitter choose the style. */ + YAML_ANY_MAPPING_STYLE, + + /** The block mapping style. */ + YAML_BLOCK_MAPPING_STYLE, + /** The flow mapping style. */ + YAML_FLOW_MAPPING_STYLE + /* YAML_FLOW_SET_MAPPING_STYLE */ +} yaml_mapping_style_t; + +/** @} */ + +/** + * @defgroup tokens Tokens + * @{ + */ + +/** Token types. */ +typedef enum yaml_token_type_e +{ + /** An empty token. */ + YAML_NO_TOKEN, + + /** A STREAM-START token. */ + YAML_STREAM_START_TOKEN, + /** A STREAM-END token. */ + YAML_STREAM_END_TOKEN, + + /** A VERSION-DIRECTIVE token. */ + YAML_VERSION_DIRECTIVE_TOKEN, + /** A TAG-DIRECTIVE token. */ + YAML_TAG_DIRECTIVE_TOKEN, + /** A DOCUMENT-START token. */ + YAML_DOCUMENT_START_TOKEN, + /** A DOCUMENT-END token. */ + YAML_DOCUMENT_END_TOKEN, + + /** A BLOCK-SEQUENCE-START token. */ + YAML_BLOCK_SEQUENCE_START_TOKEN, + /** A BLOCK-SEQUENCE-END token. */ + YAML_BLOCK_MAPPING_START_TOKEN, + /** A BLOCK-END token. */ + YAML_BLOCK_END_TOKEN, + + /** A FLOW-SEQUENCE-START token. */ + YAML_FLOW_SEQUENCE_START_TOKEN, + /** A FLOW-SEQUENCE-END token. */ + YAML_FLOW_SEQUENCE_END_TOKEN, + /** A FLOW-MAPPING-START token. */ + YAML_FLOW_MAPPING_START_TOKEN, + /** A FLOW-MAPPING-END token. */ + YAML_FLOW_MAPPING_END_TOKEN, + + /** A BLOCK-ENTRY token. */ + YAML_BLOCK_ENTRY_TOKEN, + /** A FLOW-ENTRY token. */ + YAML_FLOW_ENTRY_TOKEN, + /** A KEY token. */ + YAML_KEY_TOKEN, + /** A VALUE token. */ + YAML_VALUE_TOKEN, + + /** An ALIAS token. */ + YAML_ALIAS_TOKEN, + /** An ANCHOR token. */ + YAML_ANCHOR_TOKEN, + /** A TAG token. */ + YAML_TAG_TOKEN, + /** A SCALAR token. */ + YAML_SCALAR_TOKEN +} yaml_token_type_t; + +/** The token structure. */ +typedef struct yaml_token_s +{ + + /** The token type. */ + yaml_token_type_t type; + + /** The token data. */ + union + { + + /** The stream start (for @c YAML_STREAM_START_TOKEN). */ + struct + { + /** The stream encoding. */ + yaml_encoding_t encoding; + } stream_start; + + /** The alias (for @c YAML_ALIAS_TOKEN). */ + struct + { + /** The alias value. */ + yaml_char_t *value; + } alias; + + /** The anchor (for @c YAML_ANCHOR_TOKEN). */ + struct + { + /** The anchor value. */ + yaml_char_t *value; + } anchor; + + /** The tag (for @c YAML_TAG_TOKEN). */ + struct + { + /** The tag handle. */ + yaml_char_t *handle; + /** The tag suffix. */ + yaml_char_t *suffix; + } tag; + + /** The scalar value (for @c YAML_SCALAR_TOKEN). */ + struct + { + /** The scalar value. */ + yaml_char_t *value; + /** The length of the scalar value. */ + size_t length; + /** The scalar style. */ + yaml_scalar_style_t style; + } scalar; + + /** The version directive (for @c YAML_VERSION_DIRECTIVE_TOKEN). */ + struct + { + /** The major version number. */ + int major; + /** The minor version number. */ + int minor; + } version_directive; + + /** The tag directive (for @c YAML_TAG_DIRECTIVE_TOKEN). */ + struct + { + /** The tag handle. */ + yaml_char_t *handle; + /** The tag prefix. */ + yaml_char_t *prefix; + } tag_directive; + + } data; + + /** The beginning of the token. */ + yaml_mark_t start_mark; + /** The end of the token. */ + yaml_mark_t end_mark; + +} yaml_token_t; + +/** + * Free any memory allocated for a token object. + * + * @param[in,out] token A token object. + */ + +YAML_DECLARE(void) +yaml_token_delete(yaml_token_t *token); + +/** @} */ + +/** + * @defgroup events Events + * @{ + */ + +/** Event types. */ +typedef enum yaml_event_type_e +{ + /** An empty event. */ + YAML_NO_EVENT, + + /** A STREAM-START event. */ + YAML_STREAM_START_EVENT, + /** A STREAM-END event. */ + YAML_STREAM_END_EVENT, + + /** A DOCUMENT-START event. */ + YAML_DOCUMENT_START_EVENT, + /** A DOCUMENT-END event. */ + YAML_DOCUMENT_END_EVENT, + + /** An ALIAS event. */ + YAML_ALIAS_EVENT, + /** A SCALAR event. */ + YAML_SCALAR_EVENT, + + /** A SEQUENCE-START event. */ + YAML_SEQUENCE_START_EVENT, + /** A SEQUENCE-END event. */ + YAML_SEQUENCE_END_EVENT, + + /** A MAPPING-START event. */ + YAML_MAPPING_START_EVENT, + /** A MAPPING-END event. */ + YAML_MAPPING_END_EVENT +} yaml_event_type_t; + +/** The event structure. */ +typedef struct yaml_event_s +{ + + /** The event type. */ + yaml_event_type_t type; + + /** The event data. */ + union + { + + /** The stream parameters (for @c YAML_STREAM_START_EVENT). */ + struct + { + /** The document encoding. */ + yaml_encoding_t encoding; + } stream_start; + + /** The document parameters (for @c YAML_DOCUMENT_START_EVENT). */ + struct + { + /** The version directive. */ + yaml_version_directive_t *version_directive; + + /** The list of tag directives. */ + struct + { + /** The beginning of the tag directives list. */ + yaml_tag_directive_t *start; + /** The end of the tag directives list. */ + yaml_tag_directive_t *end; + } tag_directives; + + /** Is the document indicator implicit? */ + int implicit; + } document_start; + + /** The document end parameters (for @c YAML_DOCUMENT_END_EVENT). */ + struct + { + /** Is the document end indicator implicit? */ + int implicit; + } document_end; + + /** The alias parameters (for @c YAML_ALIAS_EVENT). */ + struct + { + /** The anchor. */ + yaml_char_t *anchor; + } alias; + + /** The scalar parameters (for @c YAML_SCALAR_EVENT). */ + struct + { + /** The anchor. */ + yaml_char_t *anchor; + /** The tag. */ + yaml_char_t *tag; + /** The scalar value. */ + yaml_char_t *value; + /** The length of the scalar value. */ + size_t length; + /** Is the tag optional for the plain style? */ + int plain_implicit; + /** Is the tag optional for any non-plain style? */ + int quoted_implicit; + /** The scalar style. */ + yaml_scalar_style_t style; + } scalar; + + /** The sequence parameters (for @c YAML_SEQUENCE_START_EVENT). */ + struct + { + /** The anchor. */ + yaml_char_t *anchor; + /** The tag. */ + yaml_char_t *tag; + /** Is the tag optional? */ + int implicit; + /** The sequence style. */ + yaml_sequence_style_t style; + } sequence_start; + + /** The mapping parameters (for @c YAML_MAPPING_START_EVENT). */ + struct + { + /** The anchor. */ + yaml_char_t *anchor; + /** The tag. */ + yaml_char_t *tag; + /** Is the tag optional? */ + int implicit; + /** The mapping style. */ + yaml_mapping_style_t style; + } mapping_start; + + } data; + + /** The beginning of the event. */ + yaml_mark_t start_mark; + /** The end of the event. */ + yaml_mark_t end_mark; + +} yaml_event_t; + +/** + * Create the STREAM-START event. + * + * @param[out] event An empty event object. + * @param[in] encoding The stream encoding. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_stream_start_event_initialize(yaml_event_t *event, + yaml_encoding_t encoding); + +/** + * Create the STREAM-END event. + * + * @param[out] event An empty event object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_stream_end_event_initialize(yaml_event_t *event); + +/** + * Create the DOCUMENT-START event. + * + * The @a implicit argument is considered as a stylistic parameter and may be + * ignored by the emitter. + * + * @param[out] event An empty event object. + * @param[in] version_directive The %YAML directive value or + * @c NULL. + * @param[in] tag_directives_start The beginning of the %TAG + * directives list. + * @param[in] tag_directives_end The end of the %TAG directives + * list. + * @param[in] implicit If the document start indicator is + * implicit. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_start_event_initialize(yaml_event_t *event, + yaml_version_directive_t *version_directive, + yaml_tag_directive_t *tag_directives_start, + yaml_tag_directive_t *tag_directives_end, + int implicit); + +/** + * Create the DOCUMENT-END event. + * + * The @a implicit argument is considered as a stylistic parameter and may be + * ignored by the emitter. + * + * @param[out] event An empty event object. + * @param[in] implicit If the document end indicator is implicit. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_end_event_initialize(yaml_event_t *event, int implicit); + +/** + * Create an ALIAS event. + * + * @param[out] event An empty event object. + * @param[in] anchor The anchor value. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_alias_event_initialize(yaml_event_t *event, yaml_char_t *anchor); + +/** + * Create a SCALAR event. + * + * The @a style argument may be ignored by the emitter. + * + * Either the @a tag attribute or one of the @a plain_implicit and + * @a quoted_implicit flags must be set. + * + * @param[out] event An empty event object. + * @param[in] anchor The scalar anchor or @c NULL. + * @param[in] tag The scalar tag or @c NULL. + * @param[in] value The scalar value. + * @param[in] length The length of the scalar value. + * @param[in] plain_implicit If the tag may be omitted for the plain + * style. + * @param[in] quoted_implicit If the tag may be omitted for any + * non-plain style. + * @param[in] style The scalar style. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_scalar_event_initialize(yaml_event_t *event, + yaml_char_t *anchor, yaml_char_t *tag, + yaml_char_t *value, int length, + int plain_implicit, int quoted_implicit, + yaml_scalar_style_t style); + +/** + * Create a SEQUENCE-START event. + * + * The @a style argument may be ignored by the emitter. + * + * Either the @a tag attribute or the @a implicit flag must be set. + * + * @param[out] event An empty event object. + * @param[in] anchor The sequence anchor or @c NULL. + * @param[in] tag The sequence tag or @c NULL. + * @param[in] implicit If the tag may be omitted. + * @param[in] style The sequence style. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_sequence_start_event_initialize(yaml_event_t *event, + yaml_char_t *anchor, yaml_char_t *tag, int implicit, + yaml_sequence_style_t style); + +/** + * Create a SEQUENCE-END event. + * + * @param[out] event An empty event object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_sequence_end_event_initialize(yaml_event_t *event); + +/** + * Create a MAPPING-START event. + * + * The @a style argument may be ignored by the emitter. + * + * Either the @a tag attribute or the @a implicit flag must be set. + * + * @param[out] event An empty event object. + * @param[in] anchor The mapping anchor or @c NULL. + * @param[in] tag The mapping tag or @c NULL. + * @param[in] implicit If the tag may be omitted. + * @param[in] style The mapping style. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_mapping_start_event_initialize(yaml_event_t *event, + yaml_char_t *anchor, yaml_char_t *tag, int implicit, + yaml_mapping_style_t style); + +/** + * Create a MAPPING-END event. + * + * @param[out] event An empty event object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_mapping_end_event_initialize(yaml_event_t *event); + +/** + * Free any memory allocated for an event object. + * + * @param[in,out] event An event object. + */ + +YAML_DECLARE(void) +yaml_event_delete(yaml_event_t *event); + +/** @} */ + +/** + * @defgroup nodes Nodes + * @{ + */ + +/** The tag @c !!null with the only possible value: @c null. */ +#define YAML_NULL_TAG "tag:yaml.org,2002:null" +/** The tag @c !!bool with the values: @c true and @c falce. */ +#define YAML_BOOL_TAG "tag:yaml.org,2002:bool" +/** The tag @c !!str for string values. */ +#define YAML_STR_TAG "tag:yaml.org,2002:str" +/** The tag @c !!int for integer values. */ +#define YAML_INT_TAG "tag:yaml.org,2002:int" +/** The tag @c !!float for float values. */ +#define YAML_FLOAT_TAG "tag:yaml.org,2002:float" +/** The tag @c !!timestamp for date and time values. */ +#define YAML_TIMESTAMP_TAG "tag:yaml.org,2002:timestamp" + +/** The tag @c !!seq is used to denote sequences. */ +#define YAML_SEQ_TAG "tag:yaml.org,2002:seq" +/** The tag @c !!map is used to denote mapping. */ +#define YAML_MAP_TAG "tag:yaml.org,2002:map" + +/** The default scalar tag is @c !!str. */ +#define YAML_DEFAULT_SCALAR_TAG YAML_STR_TAG +/** The default sequence tag is @c !!seq. */ +#define YAML_DEFAULT_SEQUENCE_TAG YAML_SEQ_TAG +/** The default mapping tag is @c !!map. */ +#define YAML_DEFAULT_MAPPING_TAG YAML_MAP_TAG + +/** Node types. */ +typedef enum yaml_node_type_e +{ + /** An empty node. */ + YAML_NO_NODE, + + /** A scalar node. */ + YAML_SCALAR_NODE, + /** A sequence node. */ + YAML_SEQUENCE_NODE, + /** A mapping node. */ + YAML_MAPPING_NODE +} yaml_node_type_t; + +/** The forward definition of a document node structure. */ +typedef struct yaml_node_s yaml_node_t; + +/** An element of a sequence node. */ +typedef int yaml_node_item_t; + +/** An element of a mapping node. */ +typedef struct yaml_node_pair_s +{ + /** The key of the element. */ + int key; + /** The value of the element. */ + int value; +} yaml_node_pair_t; + +/** The node structure. */ +struct yaml_node_s +{ + + /** The node type. */ + yaml_node_type_t type; + + /** The node tag. */ + yaml_char_t *tag; + + /** The node data. */ + union + { + + /** The scalar parameters (for @c YAML_SCALAR_NODE). */ + struct + { + /** The scalar value. */ + yaml_char_t *value; + /** The length of the scalar value. */ + size_t length; + /** The scalar style. */ + yaml_scalar_style_t style; + } scalar; + + /** The sequence parameters (for @c YAML_SEQUENCE_NODE). */ + struct + { + /** The stack of sequence items. */ + struct + { + /** The beginning of the stack. */ + yaml_node_item_t *start; + /** The end of the stack. */ + yaml_node_item_t *end; + /** The top of the stack. */ + yaml_node_item_t *top; + } items; + /** The sequence style. */ + yaml_sequence_style_t style; + } sequence; + + /** The mapping parameters (for @c YAML_MAPPING_NODE). */ + struct + { + /** The stack of mapping pairs (key, value). */ + struct + { + /** The beginning of the stack. */ + yaml_node_pair_t *start; + /** The end of the stack. */ + yaml_node_pair_t *end; + /** The top of the stack. */ + yaml_node_pair_t *top; + } pairs; + /** The mapping style. */ + yaml_mapping_style_t style; + } mapping; + + } data; + + /** The beginning of the node. */ + yaml_mark_t start_mark; + /** The end of the node. */ + yaml_mark_t end_mark; + +}; + +/** The document structure. */ +typedef struct yaml_document_s +{ + + /** The document nodes. */ + struct + { + /** The beginning of the stack. */ + yaml_node_t *start; + /** The end of the stack. */ + yaml_node_t *end; + /** The top of the stack. */ + yaml_node_t *top; + } nodes; + + /** The version directive. */ + yaml_version_directive_t *version_directive; + + /** The list of tag directives. */ + struct + { + /** The beginning of the tag directives list. */ + yaml_tag_directive_t *start; + /** The end of the tag directives list. */ + yaml_tag_directive_t *end; + } tag_directives; + + /** Is the document start indicator implicit? */ + int start_implicit; + /** Is the document end indicator implicit? */ + int end_implicit; + + /** The beginning of the document. */ + yaml_mark_t start_mark; + /** The end of the document. */ + yaml_mark_t end_mark; + +} yaml_document_t; + +/** + * Create a YAML document. + * + * @param[out] document An empty document object. + * @param[in] version_directive The %YAML directive value or + * @c NULL. + * @param[in] tag_directives_start The beginning of the %TAG + * directives list. + * @param[in] tag_directives_end The end of the %TAG directives + * list. + * @param[in] start_implicit If the document start indicator is + * implicit. + * @param[in] end_implicit If the document end indicator is + * implicit. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_initialize(yaml_document_t *document, + yaml_version_directive_t *version_directive, + yaml_tag_directive_t *tag_directives_start, + yaml_tag_directive_t *tag_directives_end, + int start_implicit, int end_implicit); + +/** + * Delete a YAML document and all its nodes. + * + * @param[in,out] document A document object. + */ + +YAML_DECLARE(void) +yaml_document_delete(yaml_document_t *document); + +/** + * Get a node of a YAML document. + * + * The pointer returned by this function is valid until any of the functions + * modifying the documents are called. + * + * @param[in] document A document object. + * @param[in] index The node id. + * + * @returns the node objct or @c NULL if @c node_id is out of range. + */ + +YAML_DECLARE(yaml_node_t *) +yaml_document_get_node(yaml_document_t *document, int index); + +/** + * Get the root of a YAML document node. + * + * The root object is the first object added to the document. + * + * The pointer returned by this function is valid until any of the functions + * modifying the documents are called. + * + * An empty document produced by the parser signifies the end of a YAML + * stream. + * + * @param[in] document A document object. + * + * @returns the node object or @c NULL if the document is empty. + */ + +YAML_DECLARE(yaml_node_t *) +yaml_document_get_root_node(yaml_document_t *document); + +/** + * Create a SCALAR node and attach it to the document. + * + * The @a style argument may be ignored by the emitter. + * + * @param[in,out] document A document object. + * @param[in] tag The scalar tag. + * @param[in] value The scalar value. + * @param[in] length The length of the scalar value. + * @param[in] style The scalar style. + * + * @returns the node id or @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_add_scalar(yaml_document_t *document, + yaml_char_t *tag, yaml_char_t *value, int length, + yaml_scalar_style_t style); + +/** + * Create a SEQUENCE node and attach it to the document. + * + * The @a style argument may be ignored by the emitter. + * + * @param[in,out] document A document object. + * @param[in] tag The sequence tag. + * @param[in] style The sequence style. + * + * @returns the node id or @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_add_sequence(yaml_document_t *document, + yaml_char_t *tag, yaml_sequence_style_t style); + +/** + * Create a MAPPING node and attach it to the document. + * + * The @a style argument may be ignored by the emitter. + * + * @param[in,out] document A document object. + * @param[in] tag The sequence tag. + * @param[in] style The sequence style. + * + * @returns the node id or @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_add_mapping(yaml_document_t *document, + yaml_char_t *tag, yaml_mapping_style_t style); + +/** + * Add an item to a SEQUENCE node. + * + * @param[in,out] document A document object. + * @param[in] sequence The sequence node id. + * @param[in] item The item node id. +* + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_append_sequence_item(yaml_document_t *document, + int sequence, int item); + +/** + * Add a pair of a key and a value to a MAPPING node. + * + * @param[in,out] document A document object. + * @param[in] mapping The mapping node id. + * @param[in] key The key node id. + * @param[in] value The value node id. +* + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_document_append_mapping_pair(yaml_document_t *document, + int mapping, int key, int value); + +/** @} */ + +/** + * @defgroup parser Parser Definitions + * @{ + */ + +/** + * The prototype of a read handler. + * + * The read handler is called when the parser needs to read more bytes from the + * source. The handler should write not more than @a size bytes to the @a + * buffer. The number of written bytes should be set to the @a length variable. + * + * @param[in,out] data A pointer to an application data specified by + * yaml_parser_set_input(). + * @param[out] buffer The buffer to write the data from the source. + * @param[in] size The size of the buffer. + * @param[out] size_read The actual number of bytes read from the source. + * + * @returns On success, the handler should return @c 1. If the handler failed, + * the returned value should be @c 0. On EOF, the handler should set the + * @a size_read to @c 0 and return @c 1. + */ + +typedef int yaml_read_handler_t(void *data, unsigned char *buffer, size_t size, + size_t *size_read); + +/** + * This structure holds information about a potential simple key. + */ + +typedef struct yaml_simple_key_s +{ + /** Is a simple key possible? */ + int possible; + + /** Is a simple key required? */ + int required; + + /** The number of the token. */ + size_t token_number; + + /** The position mark. */ + yaml_mark_t mark; +} yaml_simple_key_t; + +/** + * The states of the parser. + */ +typedef enum yaml_parser_state_e +{ + /** Expect STREAM-START. */ + YAML_PARSE_STREAM_START_STATE, + /** Expect the beginning of an implicit document. */ + YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE, + /** Expect DOCUMENT-START. */ + YAML_PARSE_DOCUMENT_START_STATE, + /** Expect the content of a document. */ + YAML_PARSE_DOCUMENT_CONTENT_STATE, + /** Expect DOCUMENT-END. */ + YAML_PARSE_DOCUMENT_END_STATE, + /** Expect a block node. */ + YAML_PARSE_BLOCK_NODE_STATE, + /** Expect a block node or indentless sequence. */ + YAML_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE, + /** Expect a flow node. */ + YAML_PARSE_FLOW_NODE_STATE, + /** Expect the first entry of a block sequence. */ + YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE, + /** Expect an entry of a block sequence. */ + YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE, + /** Expect an entry of an indentless sequence. */ + YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE, + /** Expect the first key of a block mapping. */ + YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE, + /** Expect a block mapping key. */ + YAML_PARSE_BLOCK_MAPPING_KEY_STATE, + /** Expect a block mapping value. */ + YAML_PARSE_BLOCK_MAPPING_VALUE_STATE, + /** Expect the first entry of a flow sequence. */ + YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE, + /** Expect an entry of a flow sequence. */ + YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE, + /** Expect a key of an ordered mapping. */ + YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE, + /** Expect a value of an ordered mapping. */ + YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE, + /** Expect the and of an ordered mapping entry. */ + YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE, + /** Expect the first key of a flow mapping. */ + YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE, + /** Expect a key of a flow mapping. */ + YAML_PARSE_FLOW_MAPPING_KEY_STATE, + /** Expect a value of a flow mapping. */ + YAML_PARSE_FLOW_MAPPING_VALUE_STATE, + /** Expect an empty value of a flow mapping. */ + YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE, + /** Expect nothing. */ + YAML_PARSE_END_STATE +} yaml_parser_state_t; + +/** + * This structure holds aliases data. + */ + +typedef struct yaml_alias_data_s +{ + /** The anchor. */ + yaml_char_t *anchor; + /** The node id. */ + int index; + /** The anchor mark. */ + yaml_mark_t mark; +} yaml_alias_data_t; + +/** + * The parser structure. + * + * All members are internal. Manage the structure using the @c yaml_parser_ + * family of functions. + */ + +typedef struct yaml_parser_s +{ + + /** + * @name Error handling + * @{ + */ + + /** Error type. */ + yaml_error_type_t error; + /** Error description. */ + const char *problem; + /** The byte about which the problem occured. */ + size_t problem_offset; + /** The problematic value (@c -1 is none). */ + int problem_value; + /** The problem position. */ + yaml_mark_t problem_mark; + /** The error context. */ + const char *context; + /** The context position. */ + yaml_mark_t context_mark; + + /** + * @} + */ + + /** + * @name Reader stuff + * @{ + */ + + /** Read handler. */ + yaml_read_handler_t *read_handler; + + /** A pointer for passing to the read handler. */ + void *read_handler_data; + + /** Standard (string or file) input data. */ + union + { + /** String input data. */ + struct + { + /** The string start pointer. */ + const unsigned char *start; + /** The string end pointer. */ + const unsigned char *end; + /** The string current position. */ + const unsigned char *current; + } string; + + /** File input data. */ + FILE *file; + } input; + + /** EOF flag */ + int eof; + + /** The working buffer. */ + struct + { + /** The beginning of the buffer. */ + yaml_char_t *start; + /** The end of the buffer. */ + yaml_char_t *end; + /** The current position of the buffer. */ + yaml_char_t *pointer; + /** The last filled position of the buffer. */ + yaml_char_t *last; + } buffer; + + /* The number of unread characters in the buffer. */ + size_t unread; + + /** The raw buffer. */ + struct + { + /** The beginning of the buffer. */ + unsigned char *start; + /** The end of the buffer. */ + unsigned char *end; + /** The current position of the buffer. */ + unsigned char *pointer; + /** The last filled position of the buffer. */ + unsigned char *last; + } raw_buffer; + + /** The input encoding. */ + yaml_encoding_t encoding; + + /** The offset of the current position (in bytes). */ + size_t offset; + + /** The mark of the current position. */ + yaml_mark_t mark; + + /** + * @} + */ + + /** + * @name Scanner stuff + * @{ + */ + + /** Have we started to scan the input stream? */ + int stream_start_produced; + + /** Have we reached the end of the input stream? */ + int stream_end_produced; + + /** The number of unclosed '[' and '{' indicators. */ + int flow_level; + + /** The tokens queue. */ + struct + { + /** The beginning of the tokens queue. */ + yaml_token_t *start; + /** The end of the tokens queue. */ + yaml_token_t *end; + /** The head of the tokens queue. */ + yaml_token_t *head; + /** The tail of the tokens queue. */ + yaml_token_t *tail; + } tokens; + + /** The number of tokens fetched from the queue. */ + size_t tokens_parsed; + + /* Does the tokens queue contain a token ready for dequeueing. */ + int token_available; + + /** The indentation levels stack. */ + struct + { + /** The beginning of the stack. */ + int *start; + /** The end of the stack. */ + int *end; + /** The top of the stack. */ + int *top; + } indents; + + /** The current indentation level. */ + int indent; + + /** May a simple key occur at the current position? */ + int simple_key_allowed; + + /** The stack of simple keys. */ + struct + { + /** The beginning of the stack. */ + yaml_simple_key_t *start; + /** The end of the stack. */ + yaml_simple_key_t *end; + /** The top of the stack. */ + yaml_simple_key_t *top; + } simple_keys; + + /** + * @} + */ + + /** + * @name Parser stuff + * @{ + */ + + /** The parser states stack. */ + struct + { + /** The beginning of the stack. */ + yaml_parser_state_t *start; + /** The end of the stack. */ + yaml_parser_state_t *end; + /** The top of the stack. */ + yaml_parser_state_t *top; + } states; + + /** The current parser state. */ + yaml_parser_state_t state; + + /** The stack of marks. */ + struct + { + /** The beginning of the stack. */ + yaml_mark_t *start; + /** The end of the stack. */ + yaml_mark_t *end; + /** The top of the stack. */ + yaml_mark_t *top; + } marks; + + /** The list of TAG directives. */ + struct + { + /** The beginning of the list. */ + yaml_tag_directive_t *start; + /** The end of the list. */ + yaml_tag_directive_t *end; + /** The top of the list. */ + yaml_tag_directive_t *top; + } tag_directives; + + /** + * @} + */ + + /** + * @name Dumper stuff + * @{ + */ + + /** The alias data. */ + struct + { + /** The beginning of the list. */ + yaml_alias_data_t *start; + /** The end of the list. */ + yaml_alias_data_t *end; + /** The top of the list. */ + yaml_alias_data_t *top; + } aliases; + + /** The currently parsed document. */ + yaml_document_t *document; + + /** + * @} + */ + +} yaml_parser_t; + +/** + * Initialize a parser. + * + * This function creates a new parser object. An application is responsible + * for destroying the object using the yaml_parser_delete() function. + * + * @param[out] parser An empty parser object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_parser_initialize(yaml_parser_t *parser); + +/** + * Destroy a parser. + * + * @param[in,out] parser A parser object. + */ + +YAML_DECLARE(void) +yaml_parser_delete(yaml_parser_t *parser); + +/** + * Set a string input. + * + * Note that the @a input pointer must be valid while the @a parser object + * exists. The application is responsible for destroing @a input after + * destroying the @a parser. + * + * @param[in,out] parser A parser object. + * @param[in] input A source data. + * @param[in] size The length of the source data in bytes. + */ + +YAML_DECLARE(void) +yaml_parser_set_input_string(yaml_parser_t *parser, + const unsigned char *input, size_t size); + +/** + * Set a file input. + * + * @a file should be a file object open for reading. The application is + * responsible for closing the @a file. + * + * @param[in,out] parser A parser object. + * @param[in] file An open file. + */ + +YAML_DECLARE(void) +yaml_parser_set_input_file(yaml_parser_t *parser, FILE *file); + +/** + * Set a generic input handler. + * + * @param[in,out] parser A parser object. + * @param[in] handler A read handler. + * @param[in] data Any application data for passing to the read + * handler. + */ + +YAML_DECLARE(void) +yaml_parser_set_input(yaml_parser_t *parser, + yaml_read_handler_t *handler, void *data); + +/** + * Set the source encoding. + * + * @param[in,out] parser A parser object. + * @param[in] encoding The source encoding. + */ + +YAML_DECLARE(void) +yaml_parser_set_encoding(yaml_parser_t *parser, yaml_encoding_t encoding); + +/** + * Scan the input stream and produce the next token. + * + * Call the function subsequently to produce a sequence of tokens corresponding + * to the input stream. The initial token has the type + * @c YAML_STREAM_START_TOKEN while the ending token has the type + * @c YAML_STREAM_END_TOKEN. + * + * An application is responsible for freeing any buffers associated with the + * produced token object using the @c yaml_token_delete function. + * + * An application must not alternate the calls of yaml_parser_scan() with the + * calls of yaml_parser_parse() or yaml_parser_load(). Doing this will break + * the parser. + * + * @param[in,out] parser A parser object. + * @param[out] token An empty token object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_parser_scan(yaml_parser_t *parser, yaml_token_t *token); + +/** + * Parse the input stream and produce the next parsing event. + * + * Call the function subsequently to produce a sequence of events corresponding + * to the input stream. The initial event has the type + * @c YAML_STREAM_START_EVENT while the ending event has the type + * @c YAML_STREAM_END_EVENT. + * + * An application is responsible for freeing any buffers associated with the + * produced event object using the yaml_event_delete() function. + * + * An application must not alternate the calls of yaml_parser_parse() with the + * calls of yaml_parser_scan() or yaml_parser_load(). Doing this will break the + * parser. + * + * @param[in,out] parser A parser object. + * @param[out] event An empty event object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_parser_parse(yaml_parser_t *parser, yaml_event_t *event); + +/** + * Parse the input stream and produce the next YAML document. + * + * Call this function subsequently to produce a sequence of documents + * constituting the input stream. + * + * If the produced document has no root node, it means that the document + * end has been reached. + * + * An application is responsible for freeing any data associated with the + * produced document object using the yaml_document_delete() function. + * + * An application must not alternate the calls of yaml_parser_load() with the + * calls of yaml_parser_scan() or yaml_parser_parse(). Doing this will break + * the parser. + * + * @param[in,out] parser A parser object. + * @param[out] document An empty document object. + * + * @return @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_parser_load(yaml_parser_t *parser, yaml_document_t *document); + +/** @} */ + +/** + * @defgroup emitter Emitter Definitions + * @{ + */ + +/** + * The prototype of a write handler. + * + * The write handler is called when the emitter needs to flush the accumulated + * characters to the output. The handler should write @a size bytes of the + * @a buffer to the output. + * + * @param[in,out] data A pointer to an application data specified by + * yaml_emitter_set_output(). + * @param[in] buffer The buffer with bytes to be written. + * @param[in] size The size of the buffer. + * + * @returns On success, the handler should return @c 1. If the handler failed, + * the returned value should be @c 0. + */ + +typedef int yaml_write_handler_t(void *data, unsigned char *buffer, size_t size); + +/** The emitter states. */ +typedef enum yaml_emitter_state_e +{ + /** Expect STREAM-START. */ + YAML_EMIT_STREAM_START_STATE, + /** Expect the first DOCUMENT-START or STREAM-END. */ + YAML_EMIT_FIRST_DOCUMENT_START_STATE, + /** Expect DOCUMENT-START or STREAM-END. */ + YAML_EMIT_DOCUMENT_START_STATE, + /** Expect the content of a document. */ + YAML_EMIT_DOCUMENT_CONTENT_STATE, + /** Expect DOCUMENT-END. */ + YAML_EMIT_DOCUMENT_END_STATE, + /** Expect the first item of a flow sequence. */ + YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE, + /** Expect an item of a flow sequence. */ + YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE, + /** Expect the first key of a flow mapping. */ + YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE, + /** Expect a key of a flow mapping. */ + YAML_EMIT_FLOW_MAPPING_KEY_STATE, + /** Expect a value for a simple key of a flow mapping. */ + YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE, + /** Expect a value of a flow mapping. */ + YAML_EMIT_FLOW_MAPPING_VALUE_STATE, + /** Expect the first item of a block sequence. */ + YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE, + /** Expect an item of a block sequence. */ + YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE, + /** Expect the first key of a block mapping. */ + YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE, + /** Expect the key of a block mapping. */ + YAML_EMIT_BLOCK_MAPPING_KEY_STATE, + /** Expect a value for a simple key of a block mapping. */ + YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE, + /** Expect a value of a block mapping. */ + YAML_EMIT_BLOCK_MAPPING_VALUE_STATE, + /** Expect nothing. */ + YAML_EMIT_END_STATE +} yaml_emitter_state_t; + +/** + * The emitter structure. + * + * All members are internal. Manage the structure using the @c yaml_emitter_ + * family of functions. + */ + +typedef struct yaml_emitter_s +{ + + /** + * @name Error handling + * @{ + */ + + /** Error type. */ + yaml_error_type_t error; + /** Error description. */ + const char *problem; + + /** + * @} + */ + + /** + * @name Writer stuff + * @{ + */ + + /** Write handler. */ + yaml_write_handler_t *write_handler; + + /** A pointer for passing to the white handler. */ + void *write_handler_data; + + /** Standard (string or file) output data. */ + union + { + /** String output data. */ + struct + { + /** The buffer pointer. */ + unsigned char *buffer; + /** The buffer size. */ + size_t size; + /** The number of written bytes. */ + size_t *size_written; + } string; + + /** File output data. */ + FILE *file; + } output; + + /** The working buffer. */ + struct + { + /** The beginning of the buffer. */ + yaml_char_t *start; + /** The end of the buffer. */ + yaml_char_t *end; + /** The current position of the buffer. */ + yaml_char_t *pointer; + /** The last filled position of the buffer. */ + yaml_char_t *last; + } buffer; + + /** The raw buffer. */ + struct + { + /** The beginning of the buffer. */ + unsigned char *start; + /** The end of the buffer. */ + unsigned char *end; + /** The current position of the buffer. */ + unsigned char *pointer; + /** The last filled position of the buffer. */ + unsigned char *last; + } raw_buffer; + + /** The stream encoding. */ + yaml_encoding_t encoding; + + /** + * @} + */ + + /** + * @name Emitter stuff + * @{ + */ + + /** If the output is in the canonical style? */ + int canonical; + /** The number of indentation spaces. */ + int best_indent; + /** The preferred width of the output lines. */ + int best_width; + /** Allow unescaped non-ASCII characters? */ + int unicode; + /** The preferred line break. */ + yaml_break_t line_break; + + /** The stack of states. */ + struct + { + /** The beginning of the stack. */ + yaml_emitter_state_t *start; + /** The end of the stack. */ + yaml_emitter_state_t *end; + /** The top of the stack. */ + yaml_emitter_state_t *top; + } states; + + /** The current emitter state. */ + yaml_emitter_state_t state; + + /** The event queue. */ + struct + { + /** The beginning of the event queue. */ + yaml_event_t *start; + /** The end of the event queue. */ + yaml_event_t *end; + /** The head of the event queue. */ + yaml_event_t *head; + /** The tail of the event queue. */ + yaml_event_t *tail; + } events; + + /** The stack of indentation levels. */ + struct + { + /** The beginning of the stack. */ + int *start; + /** The end of the stack. */ + int *end; + /** The top of the stack. */ + int *top; + } indents; + + /** The list of tag directives. */ + struct + { + /** The beginning of the list. */ + yaml_tag_directive_t *start; + /** The end of the list. */ + yaml_tag_directive_t *end; + /** The top of the list. */ + yaml_tag_directive_t *top; + } tag_directives; + + /** The current indentation level. */ + int indent; + + /** The current flow level. */ + int flow_level; + + /** Is it the document root context? */ + int root_context; + /** Is it a sequence context? */ + int sequence_context; + /** Is it a mapping context? */ + int mapping_context; + /** Is it a simple mapping key context? */ + int simple_key_context; + + /** The current line. */ + int line; + /** The current column. */ + int column; + /** If the last character was a whitespace? */ + int whitespace; + /** If the last character was an indentation character (' ', '-', '?', ':')? */ + int indention; + /** If an explicit document end is required? */ + int open_ended; + + /** Anchor analysis. */ + struct + { + /** The anchor value. */ + yaml_char_t *anchor; + /** The anchor length. */ + size_t anchor_length; + /** Is it an alias? */ + int alias; + } anchor_data; + + /** Tag analysis. */ + struct + { + /** The tag handle. */ + yaml_char_t *handle; + /** The tag handle length. */ + size_t handle_length; + /** The tag suffix. */ + yaml_char_t *suffix; + /** The tag suffix length. */ + size_t suffix_length; + } tag_data; + + /** Scalar analysis. */ + struct + { + /** The scalar value. */ + yaml_char_t *value; + /** The scalar length. */ + size_t length; + /** Does the scalar contain line breaks? */ + int multiline; + /** Can the scalar be expessed in the flow plain style? */ + int flow_plain_allowed; + /** Can the scalar be expressed in the block plain style? */ + int block_plain_allowed; + /** Can the scalar be expressed in the single quoted style? */ + int single_quoted_allowed; + /** Can the scalar be expressed in the literal or folded styles? */ + int block_allowed; + /** The output style. */ + yaml_scalar_style_t style; + } scalar_data; + + /** + * @} + */ + + /** + * @name Dumper stuff + * @{ + */ + + /** If the stream was already opened? */ + int opened; + /** If the stream was already closed? */ + int closed; + + /** The information associated with the document nodes. */ + struct + { + /** The number of references. */ + int references; + /** The anchor id. */ + int anchor; + /** If the node has been emitted? */ + int serialized; + } *anchors; + + /** The last assigned anchor id. */ + int last_anchor_id; + + /** The currently emitted document. */ + yaml_document_t *document; + + /** + * @} + */ + +} yaml_emitter_t; + +/** + * Initialize an emitter. + * + * This function creates a new emitter object. An application is responsible + * for destroying the object using the yaml_emitter_delete() function. + * + * @param[out] emitter An empty parser object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_emitter_initialize(yaml_emitter_t *emitter); + +/** + * Destroy an emitter. + * + * @param[in,out] emitter An emitter object. + */ + +YAML_DECLARE(void) +yaml_emitter_delete(yaml_emitter_t *emitter); + +/** + * Set a string output. + * + * The emitter will write the output characters to the @a output buffer of the + * size @a size. The emitter will set @a size_written to the number of written + * bytes. If the buffer is smaller than required, the emitter produces the + * YAML_WRITE_ERROR error. + * + * @param[in,out] emitter An emitter object. + * @param[in] output An output buffer. + * @param[in] size The buffer size. + * @param[in] size_written The pointer to save the number of written + * bytes. + */ + +YAML_DECLARE(void) +yaml_emitter_set_output_string(yaml_emitter_t *emitter, + unsigned char *output, size_t size, size_t *size_written); + +/** + * Set a file output. + * + * @a file should be a file object open for writing. The application is + * responsible for closing the @a file. + * + * @param[in,out] emitter An emitter object. + * @param[in] file An open file. + */ + +YAML_DECLARE(void) +yaml_emitter_set_output_file(yaml_emitter_t *emitter, FILE *file); + +/** + * Set a generic output handler. + * + * @param[in,out] emitter An emitter object. + * @param[in] handler A write handler. + * @param[in] data Any application data for passing to the write + * handler. + */ + +YAML_DECLARE(void) +yaml_emitter_set_output(yaml_emitter_t *emitter, + yaml_write_handler_t *handler, void *data); + +/** + * Set the output encoding. + * + * @param[in,out] emitter An emitter object. + * @param[in] encoding The output encoding. + */ + +YAML_DECLARE(void) +yaml_emitter_set_encoding(yaml_emitter_t *emitter, yaml_encoding_t encoding); + +/** + * Set if the output should be in the "canonical" format as in the YAML + * specification. + * + * @param[in,out] emitter An emitter object. + * @param[in] canonical If the output is canonical. + */ + +YAML_DECLARE(void) +yaml_emitter_set_canonical(yaml_emitter_t *emitter, int canonical); + +/** + * Set the intendation increment. + * + * @param[in,out] emitter An emitter object. + * @param[in] indent The indentation increment (1 < . < 10). + */ + +YAML_DECLARE(void) +yaml_emitter_set_indent(yaml_emitter_t *emitter, int indent); + +/** + * Set the preferred line width. @c -1 means unlimited. + * + * @param[in,out] emitter An emitter object. + * @param[in] width The preferred line width. + */ + +YAML_DECLARE(void) +yaml_emitter_set_width(yaml_emitter_t *emitter, int width); + +/** + * Set if unescaped non-ASCII characters are allowed. + * + * @param[in,out] emitter An emitter object. + * @param[in] unicode If unescaped Unicode characters are allowed. + */ + +YAML_DECLARE(void) +yaml_emitter_set_unicode(yaml_emitter_t *emitter, int unicode); + +/** + * Set the preferred line break. + * + * @param[in,out] emitter An emitter object. + * @param[in] line_break The preferred line break. + */ + +YAML_DECLARE(void) +yaml_emitter_set_break(yaml_emitter_t *emitter, yaml_break_t line_break); + +/** + * Emit an event. + * + * The event object may be generated using the yaml_parser_parse() function. + * The emitter takes the responsibility for the event object and destroys its + * content after it is emitted. The event object is destroyed even if the + * function fails. + * + * @param[in,out] emitter An emitter object. + * @param[in,out] event An event object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_emitter_emit(yaml_emitter_t *emitter, yaml_event_t *event); + +/** + * Start a YAML stream. + * + * This function should be used before yaml_emitter_dump() is called. + * + * @param[in,out] emitter An emitter object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_emitter_open(yaml_emitter_t *emitter); + +/** + * Finish a YAML stream. + * + * This function should be used after yaml_emitter_dump() is called. + * + * @param[in,out] emitter An emitter object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_emitter_close(yaml_emitter_t *emitter); + +/** + * Emit a YAML document. + * + * The documen object may be generated using the yaml_parser_load() function + * or the yaml_document_initialize() function. The emitter takes the + * responsibility for the document object and destoys its content after + * it is emitted. The document object is destroyedeven if the function fails. + * + * @param[in,out] emitter An emitter object. + * @param[in,out] document A document object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_emitter_dump(yaml_emitter_t *emitter, yaml_document_t *document); + +/** + * Flush the accumulated characters to the output. + * + * @param[in,out] emitter An emitter object. + * + * @returns @c 1 if the function succeeded, @c 0 on error. + */ + +YAML_DECLARE(int) +yaml_emitter_flush(yaml_emitter_t *emitter); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef YAML_H */ + diff --git a/src/include/http/CurlHandlerPool.h b/src/include/http/CurlHandlerPool.h new file mode 100644 index 0000000..a8141e0 --- /dev/null +++ b/src/include/http/CurlHandlerPool.h @@ -0,0 +1,42 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or at: +// | +// | http://www.apache.org/licenses/LICENSE-2.0 +// | +// | Unless required by applicable law or agreed to in writing, software +// | distributed under the License is distributed on an "AS IS" BASIS, +// | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// | See the License for the specific language governing permissions and +// | limitations under the License. +// +------------------------------------------------------------------------- + +#include +#include + +class CurlHandlerPool +{ +public: + explicit CurlHandlerPool(int maxHandlers) + : m_maxHandlers(maxHandlers) + , m_handlers(NULL) + , m_index(-1) + { + } + + bool Init(); + bool Destroy(); + + CURL* GetHandler(); + void ReleaseHandler(CURL* handle); + +private: + int m_maxHandlers; + + pthread_mutex_t m_lock; + CURL** m_handlers; + int m_index; +}; diff --git a/src/include/http/HttpClient.h b/src/include/http/HttpClient.h new file mode 100644 index 0000000..0eda820 --- /dev/null +++ b/src/include/http/HttpClient.h @@ -0,0 +1,65 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "CurlHandlerPool.h" +#include "QsSdkOption.h" +#include "QsConfig.h" +#include +#include +#include + +namespace QingStor +{ +namespace Http +{ +static CurlHandlerPool* gCurlPool = NULL; +static int gCurlPoolSize = 32; + +class HttpRequest; +class HttpResponse; + +/** +* HttpClient. All it does is make HttpRequests and return their response. +*/ +class QS_SDK_API HttpClient +{ +public: + HttpClient(int timeOutPeriod = 3):m_timeOutPeriod(timeOutPeriod) {}; + virtual ~HttpClient() {}; + + // Send an http request, returns the newly allocated HttpResponse + HttpResponse * SendRequest(HttpRequest *request) const; + + static void CreateGlobaleCurlPool(); + + static void DestroyGlobaleCurlPool(); + +private: + //bool m_allowRedirects; + int m_timeOutPeriod; // The timeout length of a single attempt, wthich in the unit of second. + + //Callback to read the content from the content body of the request + static size_t ReadBody(char *ptr, size_t size, size_t nmemb, void *userdata); + //callback to write the content to the response. + static size_t WriteData(char *ptr, size_t size, size_t nmemb, void *userdata); + //callback to write the headers to the response + static size_t WriteHeader(char *ptr, size_t size, size_t nmemb, void *userdata); +}; + +} // namespace Http +} // namespace QingStor diff --git a/src/include/http/HttpRequest.h b/src/include/http/HttpRequest.h new file mode 100644 index 0000000..f6da7e9 --- /dev/null +++ b/src/include/http/HttpRequest.h @@ -0,0 +1,195 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +#pragma once + +#include "http/HttpURI.h" +#include "HttpCommon.h" +#include +#include + +namespace QingStor +{ +namespace Http +{ +extern const char *CONTENT_LENGTH_HEADER; +extern const char *CONTENT_TYPE_HEADER; +extern const char *CONTENT_MD5_HEADER; +extern const char *DATE_HEADER; +extern const char *AUTHORIZATION_HEADER; + +/** +* Abstract class for representing an HttpRequest. +*/ +class QS_SDK_API HttpRequest +{ +public: + /** + * Initializes an HttpRequest object with uri and http method. + */ + HttpRequest(HttpMethod method, URI uri); + + virtual ~HttpRequest() + { + } + + /** + * Get the value of a Header based on its name. + */ + const std::string GetHeaderValue(const char *headerName) const; + + /** + * Add a header pair + */ + void SetHeaderValue(const char *headerName, const std::string &headerValue); + + void SetHeaderValue(const std::string &headerName, const std::string &headerValue); + + /** + * Deletes a header from the request by name. + */ + void DeleteHeader(const char *headerName); + + /** + * Add a query parameter pair + */ + void SetQueryStringParameter(const char* name, const std::string& value); + + void SetQueryStringParameter(const std::string &name, const std::string& value); + + /** + * Adds a content body stream to the request. This stream will be used to send the body to the endpoint. + */ + void AddContentBody(std::iostream *strContent) + { + bodyStream = strContent; + }; + + /** + * Returns true if a header exists in the request with name + */ + bool HasHeader(const char *name) const; + + /** + * Gets underlying URI object with mutation access. + */ + inline URI &GetUri() + { + return m_uri; + } + + /** + * Gets the underlying URI object. + */ + const URI &GetUri() const + { + return m_uri; + } + + /** + * Gets the collectio of all headers. + */ + inline HeaderValueCollection GetHeaders() const + { + return headerMap; + } + + /** + * Gets the collectio of all query param. + */ + inline QueryParamCollection GetQueries() const + { + return queryMap; + } + + /** + * Gets the collectio of all query param. + */ + inline std::string GetURLEncodedPath() const + { + return m_uri.GetURLEncodedPath(); + } + + /** + * Get Encoded URL + */ + inline std::string GetURIString() const + { + return m_uri.GetURIString(); + } + + /** + * Get the http method for this request. + */ + inline HttpMethod GetMethod() const + { + return m_method; + } + + /** + * Adds a query string parameter to the underlying URI by key and value. + */ + inline void AddQueryStringParameter(const char *key, const std::string &value) + { + m_uri.AddQueryStringParameter(key, value); + } + + /** + * Gets content-length header. + */ + inline const std::string GetContentLength() const + { + return GetHeaderValue(CONTENT_LENGTH_HEADER); + } + + /** + * Sets content-length header. + */ + inline void SetContentLength(const std::string &value) + { + SetHeaderValue(CONTENT_LENGTH_HEADER, value); + } + + /** + * Gets the content body stream that will be used for this request. + */ + std::iostream *GetContentBody() const + { + return bodyStream; + }; + + /** + * Release the request body. + */ + void ReleaseResponseBody() + { + if(bodyStream) + { + delete bodyStream; + bodyStream = NULL; + } + } + + +private: + std::iostream *bodyStream; + URI m_uri; + HttpMethod m_method; + HeaderValueCollection headerMap; + QueryParamCollection queryMap; +}; + +} // namespace Http +} // namespace QingStor diff --git a/src/include/http/HttpResponse.h b/src/include/http/HttpResponse.h new file mode 100644 index 0000000..5e39814 --- /dev/null +++ b/src/include/http/HttpResponse.h @@ -0,0 +1,117 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "QsSdkOption.h" +#include "http/HttpRequest.h" +#include "utils/QsStream.h" + +namespace QingStor +{ +namespace Utils +{ +namespace Stream +{ +class ResponseStream; +} +} +namespace Http +{ +/** + * Abstract class for representing an Http Response. + */ +class QS_SDK_API HttpResponse +{ +public: + /** + * Initializes an http response with the originalRequest and the response code. + */ + HttpResponse() : responseCode(REQUEST_NOT_MADE) + { + bodyStream = new QsStream(); + } + + virtual ~HttpResponse() {}; // = default; + + /** + * Get the headers from this response + */ + HeaderValueCollection GetHeaders(); + /** + * Returns true if the response contains a header by headerName + */ + bool HasHeader(const char *headerName) const; + /** + * Returns the value for a header at headerName if it exists. + */ + std::string GetHeader(const std::string &) const; + /** + * Gets response code for this http response. + */ + inline HttpResponseCode GetResponseCode() const + { + return responseCode; + } + /** + * Sets the response code for this http response. + */ + inline void SetResponseCode(HttpResponseCode httpResponseCode) + { + responseCode = httpResponseCode; + } + + /** + * Gets the response body of the response. + */ + std::iostream *GetResponseBody() + { + return bodyStream; // bodyStream.GetUnderlyingStream(); + } + + /** + * Release the response body. + */ + void ReleaseResponseBody() + { + if(bodyStream) + { + delete bodyStream; + bodyStream = NULL; + } + } + + /** + * Adds a header to the http response object. + */ + void AddHeader(const std::string &, const std::string &); + /** + * Sets the content type header on the http response object. + */ + void SetContentType(const std::string &contentType) + { + AddHeader("content-type", contentType); + }; + +private: + QsStream *bodyStream; + HttpResponseCode responseCode; + HeaderValueCollection headerMap; + +}; + +} // namespace Http +} // namespace QingStor diff --git a/src/include/http/HttpURI.h b/src/include/http/HttpURI.h new file mode 100644 index 0000000..883e761 --- /dev/null +++ b/src/include/http/HttpURI.h @@ -0,0 +1,81 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "QsSdkOption.h" +#include "HttpCommon.h" +#include +#include +#include +#include + +namespace QingStor +{ +namespace Http +{ +extern QS_SDK_API const char *SEPARATOR; + +class QS_SDK_API URI +{ +public: + + URI(const std::string &endpoint, const std::string &path, const std::string &queryString = "") ; + + /** + * Gets the raw query string including "?" + */ + inline const std::string &GetQueryString() const + { + return m_queryString; + } + + /** + * Gets the uri with every path portion encoded + */ + inline std::string GetURLEncodedPath() const + { + return URLEncodePath(m_path); + } + + /** + * Cannonicalizes the query string with filter. + */ + std::string GetFormParameters() const; + + /** + * Adds query string parameter to underlying query string. + */ + void AddQueryStringParameter(const char *key, const std::string &value); + + /** + * Get Encoded URL + */ + std::string GetURIString() const; + + /** + * URLEncodes encode portions of path (doesn't encode "/") + */ + static std::string URLEncodePath(const std::string &path); + +private: + std::string m_endpoint; + std::string m_path; + std::string m_queryString; +}; + +} // namespace Http +} // namespace QingStor diff --git a/src/include/request/QsRequest.h b/src/include/request/QsRequest.h new file mode 100644 index 0000000..1953760 --- /dev/null +++ b/src/include/request/QsRequest.h @@ -0,0 +1,102 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "QsSdkOption.h" +#include "QsErrors.h" +#include "QsConfig.h" +#include "signer/QsSigner.h" +#include "HttpCommon.h" +#include "http/HttpClient.h" +#include "http/HttpRequest.h" +#include "http/HttpResponse.h" +#include "Types.h" +#include "request/QsRequestBuilder.h" +#include "request/QsResponseUnparker.h" +#include + +using namespace QingStor; +using namespace QingStor::Http; + +class Operation +{ +public: + Operation(QsConfig *pConfig, Properties properties, std::string strApiName, HttpMethod strReqMethod, std::string strReqURI) : m_pConfig(pConfig), m_properties(properties), m_strApiName(strApiName), + m_strReqMethod(strReqMethod), m_strReqURI(strReqURI) {}; + + virtual ~Operation() {}; + + inline const QsConfig *GetConfig() const + { + return m_pConfig; + }; + inline const Properties GetProperties() const + { + return m_properties; + }; + inline const std::string GetApiName() const + { + return m_strApiName; + } + inline const HttpMethod GetReqMethod() const + { + return m_strReqMethod; + } + + inline const std::string GetReqURI() const + { + return m_strReqURI; + }; + +private: + QsConfig *m_pConfig; + Properties m_properties; + std::string m_strApiName; + HttpMethod m_strReqMethod; + std::string m_strReqURI; +}; + +class QS_SDK_API QsRequest +{ +public: + QsRequest(const Operation &operation, QsRequestBuilder *pReqBuilder, QsResponseUnparker *pRespUnparker) + : m_operation(operation), + m_signer(operation.GetConfig()->accessKeyId, operation.GetConfig()->secretAccessKey), + m_pReqBuilder(pReqBuilder), m_pRespUnpacker(pRespUnparker), + m_httpClient(operation.GetConfig()->timeOutPeriod), + httpRequest(NULL),httpResponse(NULL) {}; + + virtual ~QsRequest() {}; + + QsError GetResponse(); + +protected: + Operation m_operation; + QingStor::QsSigner m_signer; + QsRequestBuilder *m_pReqBuilder; + QsResponseUnparker *m_pRespUnpacker; + HttpClient m_httpClient; + HttpRequest* httpRequest; + HttpResponse* httpResponse; + + HttpRequest* BuildHttpRequest(); + QsError SendReqAndWait4Resp(); + void AddHeadersToRequest( Http::HttpRequest * httpRequest); + void AddContentBodyToRequest( Http::HttpRequest * httpRequest); + void AddQueryStringParameters( Http::HttpRequest * httpRequest); + QsError PareseResponse( HttpResponse* httpResponse); +}; diff --git a/src/include/request/QsRequestBuilder.h b/src/include/request/QsRequestBuilder.h new file mode 100644 index 0000000..c17293a --- /dev/null +++ b/src/include/request/QsRequestBuilder.h @@ -0,0 +1,93 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "QsSdkOption.h" +#include "QsErrors.h" +#include "QsConfig.h" +#include "signer/QsSigner.h" +#include "HttpCommon.h" +#include "http/HttpClient.h" +#include "Types.h" +#include + +using namespace QingStor; + +class QS_SDK_API QsRequestBuilder +{ +public: + /** + * Defult and Base Builder Class + */ + QsRequestBuilder() {}; + + virtual ~QsRequestBuilder() {}; + + virtual bool CkeckIfInputIsVaild() = 0; + + virtual Http::HeaderValueCollection GetHeaderValueCollection() = 0; + + virtual Http::QueryParamCollection GetQueryParamCollection() = 0; + + virtual std::iostream* GetRequestBody() = 0; + + virtual bool CkeckIfNeedReleaseBody() = 0; + +}; + + +template +class QS_SDK_API QsDefaultRequestBuilder :public QsRequestBuilder +{ +public: + /** + * Defult and Base Unparker Class + */ + QsDefaultRequestBuilder(InputType * input) :QsRequestBuilder(), m_input(input),m_bNeedReleaseBody(false) {}; + + virtual ~QsDefaultRequestBuilder() {}; + + virtual bool CkeckIfInputIsVaild() + { + return true; + }; + virtual Http::HeaderValueCollection GetHeaderValueCollection() + { + Http::HeaderValueCollection emptyCollection; + return emptyCollection; + } + + virtual Http::QueryParamCollection GetQueryParamCollection() + { + Http::QueryParamCollection emptyCollection; + return emptyCollection; + } + + virtual std::iostream* GetRequestBody() + { + return NULL; + }; + + bool CkeckIfNeedReleaseBody() + { + return m_bNeedReleaseBody; + }; + +protected: + InputType * m_input; + bool m_bNeedReleaseBody; +}; diff --git a/src/include/request/QsResponseUnparker.h b/src/include/request/QsResponseUnparker.h new file mode 100644 index 0000000..bc2113f --- /dev/null +++ b/src/include/request/QsResponseUnparker.h @@ -0,0 +1,97 @@ + +#include "external/json/json.h" + +// +class QS_SDK_API QsResponseUnparker +{ +public: + /** + * Defult and Base Unparker Class + */ + QsResponseUnparker() {}; + + virtual ~QsResponseUnparker() {}; + + virtual void ParseRequestID(const std::string &requestID) = 0; + + virtual void ParseResponseErrInfo(std::iostream * responseBody) = 0; + + virtual bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) = 0; + + virtual void ParseResponseHeaders(const Http::HeaderValueCollection &headerValueCollection)=0; + + virtual void ParseResponseBody(std::iostream *responseBody) = 0; + + virtual bool CkeckIfNeedReleaseBody() = 0; + +}; + +template +class QS_SDK_API QsDefaultResponseUnparker : public QsResponseUnparker +{ +public: + /** + * Defult and Base Unparker Class + */ + QsDefaultResponseUnparker(OutputType *output) : QsResponseUnparker(), m_output(output),m_bNeedReleaseBody(false) {}; + + virtual ~QsDefaultResponseUnparker() {}; + + virtual void ParseResponseHeaders(const Http::HeaderValueCollection &headerValueCollection) + { + return; + }; + + virtual void ParseResponseBody(std::iostream *responseBody) + { + m_bNeedReleaseBody = true; + return; + }; + + bool CkeckIfNeedReleaseBody() + { + return m_bNeedReleaseBody; + }; + + bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) + { + m_output->SetResponseCode(responseCode); + return true; + }; + + virtual void ParseRequestID(const std::string &requestID) + { + m_output->SetRequestID(requestID); + }; + + void ParseResponseErrInfo(std::iostream * responseBody) + { + QingStor::ResponseErrorInfo errorInfo; + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(*responseBody, jsonContent); + if (jsonContent.isMember("code")) + { + errorInfo.code = jsonContent["code"].asString(); + } + if (jsonContent.isMember("message")) + { + errorInfo.message = jsonContent["message"].asString(); + } + if (jsonContent.isMember("request_id")) + { + errorInfo.requestID = jsonContent["request_id"].asString(); + } + if (jsonContent.isMember("url")) + { + errorInfo.url = jsonContent["url"].asString(); + } + m_output->SetResponseErrInfo(errorInfo); + m_bNeedReleaseBody = true; + } + +protected: + OutputType *m_output; + bool m_bNeedReleaseBody; +}; diff --git a/src/include/signer/QsSigner.h b/src/include/signer/QsSigner.h new file mode 100644 index 0000000..db8de99 --- /dev/null +++ b/src/include/signer/QsSigner.h @@ -0,0 +1,44 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#include "http/HttpRequest.h" +#include "QsErrors.h" +#include + +namespace QingStor +{ + +class QS_SDK_API QsSigner +{ +public: + QsSigner(std::string strAccessKeyID, std::string strSecretAccessKey) : m_AccessKeyID(strAccessKeyID), m_strSecretAccessKey(strSecretAccessKey) {}; + virtual ~QsSigner() {}; + std::string GetTimestamp() const; + QsError SignRequest(Http::HttpRequest* request) const; + std::string BuildStringToSign(Http::HttpRequest* request) const; + +private: + std::string BuildCanonicalizedHeaders(Http::HeaderValueCollection headers) const; + std::string BuildCanonicalizedResource(Http::QueryParamCollection queryMap, std::string urlEncodedPath) const; + +private: + std::string m_AccessKeyID; + std::string m_strSecretAccessKey; +}; + +} // namespace QingStor \ No newline at end of file diff --git a/src/include/utils/QsAlloc.h b/src/include/utils/QsAlloc.h new file mode 100644 index 0000000..48a4a51 --- /dev/null +++ b/src/include/utils/QsAlloc.h @@ -0,0 +1,29 @@ +#pragma once + +#include "QsSdkOption.h" + +#include +#include + +namespace QingStor +{ + +template +T *New() +{ + void *rawMemory = malloc(sizeof(T)); + T *constructedMemory = new (rawMemory) T(); + return constructedMemory; +} + +template +void Delete(T *pointerToT) +{ + if (pointerToT == NULL) + { + return; + } + pointerToT->~T(); + free(pointerToT); +} +} \ No newline at end of file diff --git a/src/include/utils/QsEncoder.h b/src/include/utils/QsEncoder.h new file mode 100644 index 0000000..7058002 --- /dev/null +++ b/src/include/utils/QsEncoder.h @@ -0,0 +1,39 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#pragma once + +#ifndef _WIN32 +#include +#endif + +#include + +namespace QingStor +{ +namespace Utils +{ +namespace Encoder +{ +/* Encodes a binary safe base 64 string */ +std::string Base64Encode(const char *buffer, size_t length); + +void sha256hmac(const char *str, char out[33], const char *secret); + +} // namespace Encoder +} // namespace Utils +} // namespace QingStor + diff --git a/src/include/utils/QsStream.h b/src/include/utils/QsStream.h new file mode 100644 index 0000000..75bdab5 --- /dev/null +++ b/src/include/utils/QsStream.h @@ -0,0 +1,26 @@ + +#pragma once + +#include "QsSdkOption.h" +#include + +#include + +typedef std::basic_stringbuf, std::allocator > StringBuf; + +namespace QingStor +{ +class QsStream : public std::iostream +{ +public: + typedef std::iostream Base; + QsStream() : Base(QingStor::New()) {}; + virtual ~QsStream() + { + if (rdbuf()) + { + QingStor::Delete(rdbuf()); + } + }; +}; +} \ No newline at end of file diff --git a/src/request/QsRequest.cpp b/src/request/QsRequest.cpp new file mode 100644 index 0000000..3643044 --- /dev/null +++ b/src/request/QsRequest.cpp @@ -0,0 +1,268 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +#ifdef _WIN32 +#define sleep(x) Sleep((x)*1000) +#include +#else //linux +#include +#endif + +#include "plog/Log.h" +#include "QsErrors.h" +#include "http/HttpRequest.h" +#include "HttpCommon.h" +#include "http/HttpResponse.h" +#include "request/QsRequest.h" +#include + +using namespace QingStor::Utils; +using namespace QingStor::Http; + +static const char *QS_REQUEST_HEADER_REQUESTID = "X-Qs-Request-Id"; + +static const int countToEncode = 3; +static std::string headersToEncode[countToEncode] = +{ + "X-QS-Fetch-Source", + "X-QS-Copy-Source", + "X-QS-Move-Source", +}; + +void QsRequest::AddHeadersToRequest(QingStor::Http::HttpRequest* httpRequest) +{ + Http::HeaderValueCollection headerValues = m_pReqBuilder->GetHeaderValueCollection(); + for(HeaderValueCollection::iterator it = headerValues.begin(); it != headerValues.end(); it++) + { + if ("" == it->second) + { + continue; + } + bool bInHeadersToEncode = false; + for(int i =0; i < countToEncode; i++) + { + if (it->first == headersToEncode[i]) + { + bInHeadersToEncode = true; + break; + } + } + // Headers in "headersToEncode", need URL transcoding. + if(bInHeadersToEncode) + { + httpRequest->SetHeaderValue(it->first, URI::URLEncodePath(it->second)); + } + else + { + httpRequest->SetHeaderValue(it->first, it->second.c_str()); + } + } +} + +void QsRequest::AddContentBodyToRequest(QingStor::Http::HttpRequest* httpRequest) +{ + std::iostream* requestStream = NULL; + requestStream = m_pReqBuilder->GetRequestBody(); + httpRequest->AddContentBody(requestStream); + //If there is no body, content length should be 0. + if (!requestStream) + { + LOG_DEBUG << "No content body, set content-length header to 0."; + if (httpRequest->GetMethod() == HTTP_POST || httpRequest->GetMethod() == HTTP_PUT) + { + httpRequest->SetHeaderValue(Http::CONTENT_LENGTH_HEADER, "0"); + } + else + { + httpRequest->DeleteHeader(Http::CONTENT_LENGTH_HEADER); + } + } + else if (!httpRequest->HasHeader(Http::CONTENT_LENGTH_HEADER)) + { + LOG_DEBUG << "Found body, but content-length has not been set, attempting to compute content-length."; + requestStream->seekg(0, requestStream->end); + size_t streamSize = requestStream->tellg(); + requestStream->seekg(0, requestStream->beg); + std::stringstream ss; + ss << streamSize; + httpRequest->SetContentLength(ss.str()); + } +} + +void QsRequest::AddQueryStringParameters(HttpRequest* httpRequest) +{ + Http::QueryParamCollection queryParameters = m_pReqBuilder->GetQueryParamCollection(); + for(QueryParamCollection::iterator it = queryParameters.begin(); it != queryParameters.end(); it++) + { + httpRequest->SetQueryStringParameter(it->first.c_str(), it->second); + } +} + +HttpRequest* QsRequest::BuildHttpRequest() +{ + Properties props = m_operation.GetProperties(); + const QsConfig *pConfig = m_operation.GetConfig(); + std::string strZone = props.Zone; + std::string strBucketName = props.BucketName; + std::string strObjectKey = props.ObjectKey; + std::stringstream endpoint; + endpoint << pConfig->protocol << "://"; + if (strZone != "") + { + endpoint << strZone << "."; + } + endpoint << pConfig->host; + if (pConfig->port != 443 && pConfig->port != 80) + { + endpoint << ":" << pConfig->port; + } + std::string path = m_operation.GetReqURI(); + std::string queryString; + size_t queryBegin = path.find('?'); + if (queryBegin != std::string::npos) + { + queryString = path.substr(queryBegin, path.length()); + path = path.substr(0, queryBegin); + } + StringUtils::Replace(path, "", strBucketName.c_str()); + StringUtils::Replace(path, "", strObjectKey.c_str()); + StringUtils::Replace(path, "", strZone.c_str()); + URI uri(endpoint.str(), path, queryString); + HttpRequest* httpRequest = new HttpRequest(m_operation.GetReqMethod(), uri); + AddQueryStringParameters(httpRequest); + //do headers first since the request likely will set content-length as it's own header. + AddHeadersToRequest(httpRequest); + //would not compute content Md5 + AddContentBodyToRequest(httpRequest); + return httpRequest; +} + +QsError QsRequest::PareseResponse(HttpResponse* httpResponse) +{ + QsError reqErr = QS_ERR_NO_ERROR; + if (m_pRespUnpacker) + { + // check if response code is in line with expectation. + if(!m_pRespUnpacker->CheckIfResponseExpected(httpResponse->GetResponseCode())) + { + reqErr = QS_ERR_UNEXCEPTED_RESPONSE; + m_pRespUnpacker->ParseResponseErrInfo(httpResponse->GetResponseBody()); + } + else + { + m_pRespUnpacker->ParseResponseHeaders(httpResponse->GetHeaders()); + m_pRespUnpacker->ParseResponseBody(httpResponse->GetResponseBody()); + m_pRespUnpacker->ParseRequestID(httpResponse->GetHeader(QS_REQUEST_HEADER_REQUESTID)); + } + } + return reqErr; +} + +QsError QsRequest::SendReqAndWait4Resp() +{ + QsError reqErr = QS_ERR_NO_ERROR; + long maxRetries = m_operation.GetConfig()->connectionRetries; + long retries = 0; + // 1.build request content + httpRequest = BuildHttpRequest(); + do + { + // 2. sign the request + reqErr = m_signer.SignRequest(httpRequest); + if (reqErr != QS_ERR_NO_ERROR) + { + LOG_ERROR << "Sign request failed. Returning error."; + break; + } + // 3. send http request and get http response + std::iostream * reqBodyStream = httpRequest->GetContentBody(); + // record the starting position of the stream, it will be uesd in retry process. + // we can not suppose retry should begin form zero position. + size_t startingPosition = 0; + if(reqBodyStream) + { + startingPosition = reqBodyStream->tellg(); + } + httpResponse = m_httpClient.SendRequest(httpRequest); + if (httpResponse) + { + LOG_DEBUG << "Request successful returning."; + reqErr = QS_ERR_NO_ERROR; + break; + } + else + { + // if request failed, we just retry "maxRetries" times. + // We haven't implement the speed limit feature yet, so just sleep 1000ms between each retry + retries++; + LOG_WARNING << "Request failed, now attempting again." + << "retries :" << retries << "maxRetries :" << maxRetries; + if (reqBodyStream) + { + reqBodyStream->clear(); + reqBodyStream->seekg(startingPosition); + } + } + } + while (retries < maxRetries); + if(retries == maxRetries) + { + reqErr = QS_ERR_SEND_REQUEST_ERROR; + } + if (QS_ERR_NO_ERROR == reqErr) + { + LOG_DEBUG << "Get response and begin to parese."; + // 4.parese the response + reqErr = PareseResponse(httpResponse); + } + else + { + LOG_ERROR << "Send request failed. Returning error."; + } + return reqErr; +} + +QsError QsRequest::GetResponse() +{ + // Ckeck input. + if (!m_pReqBuilder->CkeckIfInputIsVaild()) + { + LOG_ERROR << "Some required parameters in request not specified. Returning error."; + return QS_ERR_NO_REQUIRED_PARAMETER; + } + // Send request and wait for response. + QsError reqErr = SendReqAndWait4Resp(); + // Clean resource. + if(httpRequest) + { + if(m_pReqBuilder->CkeckIfNeedReleaseBody()) + { + httpRequest->ReleaseResponseBody(); + } + delete httpRequest; + httpRequest = NULL; + } + if(httpResponse) + { + if(m_pRespUnpacker->CkeckIfNeedReleaseBody()) + { + httpResponse->ReleaseResponseBody(); + } + delete httpResponse; + httpResponse = NULL; + } + return reqErr; +} \ No newline at end of file diff --git a/src/service/Bucket.cpp b/src/service/Bucket.cpp new file mode 100644 index 0000000..56454e8 --- /dev/null +++ b/src/service/Bucket.cpp @@ -0,0 +1,3155 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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 "Bucket.h" +#include "StringUtils.h" +#include "request/QsRequest.h" +#include "http/HttpResponse.h" +#include "external/json/json.h" +#include +#include + +using namespace QingStor; +using namespace QingStor::Utils; + +#ifdef _WIN32 +#define GetObject GetObject +#endif + +Bucket::Bucket(const QsConfig & qsConfig, const std::string & strBucketName, const std::string & strZone):m_qsConfig + (qsConfig) +{ + m_properties.BucketName = strBucketName; + m_properties.Zone = strZone; +} + +// +-------------------------------------------------------------------- +// | RequestBuilderSource and ResponseUnparkerSource +// +-------------------------------------------------------------------- +typedef QsDefaultRequestBuilder < DeleteBucketInput > DeleteBucketBuilder; + +typedef QsDefaultResponseUnparker < DeleteBucketOutput > DeleteBucketUnparker; + +typedef QsDefaultRequestBuilder < DeleteBucketCORSInput > +DeleteBucketCORSBuilder; + +typedef QsDefaultResponseUnparker < DeleteBucketCORSOutput > +DeleteBucketCORSUnparker; + +typedef QsDefaultRequestBuilder < DeleteBucketExternalMirrorInput > +DeleteBucketExternalMirrorBuilder; + +typedef QsDefaultResponseUnparker < DeleteBucketExternalMirrorOutput > +DeleteBucketExternalMirrorUnparker; + +typedef QsDefaultRequestBuilder < DeleteBucketPolicyInput > +DeleteBucketPolicyBuilder; + +typedef QsDefaultResponseUnparker < DeleteBucketPolicyOutput > +DeleteBucketPolicyUnparker; + +class DeleteMultipleObjectsBuilder:public QsDefaultRequestBuilder < + DeleteMultipleObjectsInput > +{ +public: + DeleteMultipleObjectsBuilder(DeleteMultipleObjectsInput * + input):QsDefaultRequestBuilder < + DeleteMultipleObjectsInput > (input) + { + }; + + virtual ~ DeleteMultipleObjectsBuilder() + { + }; + + virtual bool CkeckIfInputIsVaild() + { + return m_input->CheckIfInputIsVaild(); + }; + virtual Http::HeaderValueCollection GetHeaderValueCollection(); + virtual std::iostream * GetRequestBody(); +}; + +// DeleteMultipleObjectsRequest GetRequestSpecificHeaders. +Http::HeaderValueCollection DeleteMultipleObjectsBuilder:: +GetHeaderValueCollection() +{ + //TO DO; + Http::HeaderValueCollection headers; + std::stringstream ss; + std::vector < std::string >::iterator it; + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_DELETE_MULTIPLE_OBJECTS_CONTENT_MD5_FLAG)) + { + ss << m_input->GetContentMD5(); + headers.insert(Http::HeaderValuePair("Content-MD5", ss.str())); + ss.str(""); + } + return headers; +} + +// DeleteMultipleObjectsRequest GetRequestBody. +std::iostream * DeleteMultipleObjectsBuilder::GetRequestBody() +{ + //TO DO; + Json::FastWriter jsonWriter; + Json::Value jsonContent; + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_DELETE_MULTIPLE_OBJECTS_OBJECTS_FLAG)) + { + Json::Value arrayObjects; + std::vector < KeyType > objects = m_input->GetObjects(); + for (std::vector < KeyType >::iterator it = objects.begin(); + it != objects.end(); it++) + { + Json::Reader jsonReader; + Json::Value itemJsonValue; + jsonReader.parse(it->Serialize(), itemJsonValue); + arrayObjects.append(itemJsonValue); + } + jsonContent["objects"] = arrayObjects; + } + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_DELETE_MULTIPLE_OBJECTS_QUIET_FLAG)) + { + jsonContent["quiet"] = m_input->GetQuiet(); + } + m_bNeedReleaseBody = true; + return new std::stringstream(jsonWriter.write(jsonContent)); +} + +class DeleteMultipleObjectsUnparker:public QsDefaultResponseUnparker < + DeleteMultipleObjectsOutput > +{ +public: + DeleteMultipleObjectsUnparker(DeleteMultipleObjectsOutput * + output):QsDefaultResponseUnparker < + DeleteMultipleObjectsOutput > (output) + { + }; + + virtual ~ DeleteMultipleObjectsUnparker() + { + }; + + virtual bool CkeckIfOutputIsVaild() + { + return m_output->IsVaild(); + }; + + virtual bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) + { + m_output->SetResponseCode(responseCode); + // Expected response codes. + int expectedRespCode[1] = { 200, }; + bool isExpected = false; + for (int i = 0; i < 1; i++) + { + if (expectedRespCode[i] == responseCode) + { + isExpected = true; + break; + } + } + return isExpected; + }; + virtual void ParseResponseBody(std::iostream * responseBody); +}; + +void DeleteMultipleObjectsUnparker::ParseResponseBody(std::iostream * + responseBody) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(*responseBody, jsonContent); + if (jsonContent.isMember("deleted")) + { + std::vector < KeyType > vecDeleted; + for (unsigned i = 0; i < jsonContent["deleted"].size(); ++i) + { + vecDeleted.push_back(jsonContent["deleted"][i].toStyledString()); + } + m_output->SetDeleted(vecDeleted); + } + if (jsonContent.isMember("errors")) + { + std::vector < KeyDeleteErrorType > vecErrors; + for (unsigned i = 0; i < jsonContent["errors"].size(); ++i) + { + vecErrors.push_back(jsonContent["errors"][i].toStyledString()); + } + m_output->SetErrors(vecErrors); + } + m_bNeedReleaseBody = true; +} + +typedef QsDefaultRequestBuilder < GetBucketACLInput > GetBucketACLBuilder; + +class GetBucketACLUnparker:public QsDefaultResponseUnparker < + GetBucketACLOutput > +{ +public: + GetBucketACLUnparker(GetBucketACLOutput * + output):QsDefaultResponseUnparker < + GetBucketACLOutput > (output) + { + }; + + virtual ~ GetBucketACLUnparker() + { + }; + + virtual bool CkeckIfOutputIsVaild() + { + return m_output->IsVaild(); + }; + + virtual bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) + { + m_output->SetResponseCode(responseCode); + // Expected response codes. + int expectedRespCode[1] = { 200, }; + bool isExpected = false; + for (int i = 0; i < 1; i++) + { + if (expectedRespCode[i] == responseCode) + { + isExpected = true; + break; + } + } + return isExpected; + }; + virtual void ParseResponseBody(std::iostream * responseBody); +}; + +void GetBucketACLUnparker::ParseResponseBody(std::iostream * responseBody) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(*responseBody, jsonContent); + if (jsonContent.isMember("acl")) + { + std::vector < ACLType > vecACL; + for (unsigned i = 0; i < jsonContent["acl"].size(); ++i) + { + vecACL.push_back(jsonContent["acl"][i].toStyledString()); + } + m_output->SetACL(vecACL); + } + if (jsonContent.isMember("owner")) + { + m_output->SetOwner(jsonContent["owner"].toStyledString()); + } + m_bNeedReleaseBody = true; +} + +typedef QsDefaultRequestBuilder < GetBucketCORSInput > GetBucketCORSBuilder; + +class GetBucketCORSUnparker:public QsDefaultResponseUnparker < + GetBucketCORSOutput > +{ +public: + GetBucketCORSUnparker(GetBucketCORSOutput * + output):QsDefaultResponseUnparker < + GetBucketCORSOutput > (output) + { + }; + + virtual ~ GetBucketCORSUnparker() + { + }; + + virtual bool CkeckIfOutputIsVaild() + { + return m_output->IsVaild(); + }; + + virtual bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) + { + m_output->SetResponseCode(responseCode); + // Expected response codes. + int expectedRespCode[1] = { 200, }; + bool isExpected = false; + for (int i = 0; i < 1; i++) + { + if (expectedRespCode[i] == responseCode) + { + isExpected = true; + break; + } + } + return isExpected; + }; + virtual void ParseResponseBody(std::iostream * responseBody); +}; + +void GetBucketCORSUnparker::ParseResponseBody(std::iostream * responseBody) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(*responseBody, jsonContent); + if (jsonContent.isMember("cors_rules")) + { + std::vector < CORSRuleType > vecCORSRules; + for (unsigned i = 0; i < jsonContent["cors_rules"].size(); ++i) + { + vecCORSRules.push_back(jsonContent["cors_rules"][i]. + toStyledString()); + } + m_output->SetCORSRules(vecCORSRules); + } + m_bNeedReleaseBody = true; +} + +typedef QsDefaultRequestBuilder < GetBucketExternalMirrorInput > +GetBucketExternalMirrorBuilder; + +class GetBucketExternalMirrorUnparker:public QsDefaultResponseUnparker < + GetBucketExternalMirrorOutput > +{ +public: + GetBucketExternalMirrorUnparker(GetBucketExternalMirrorOutput * + output):QsDefaultResponseUnparker < + GetBucketExternalMirrorOutput > (output) + { + }; + + virtual ~ GetBucketExternalMirrorUnparker() + { + }; + + virtual bool CkeckIfOutputIsVaild() + { + return m_output->IsVaild(); + }; + + virtual bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) + { + m_output->SetResponseCode(responseCode); + // Expected response codes. + int expectedRespCode[1] = { 200, }; + bool isExpected = false; + for (int i = 0; i < 1; i++) + { + if (expectedRespCode[i] == responseCode) + { + isExpected = true; + break; + } + } + return isExpected; + }; + virtual void ParseResponseBody(std::iostream * responseBody); +}; + +void GetBucketExternalMirrorUnparker::ParseResponseBody(std::iostream * + responseBody) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(*responseBody, jsonContent); + if (jsonContent.isMember("source_site")) + { + m_output->SetSourceSite(jsonContent["source_site"].asString()); + } + m_bNeedReleaseBody = true; +} + +typedef QsDefaultRequestBuilder < GetBucketPolicyInput > GetBucketPolicyBuilder; + +class GetBucketPolicyUnparker:public QsDefaultResponseUnparker < + GetBucketPolicyOutput > +{ +public: + GetBucketPolicyUnparker(GetBucketPolicyOutput * + output):QsDefaultResponseUnparker < + GetBucketPolicyOutput > (output) + { + }; + + virtual ~ GetBucketPolicyUnparker() + { + }; + + virtual bool CkeckIfOutputIsVaild() + { + return m_output->IsVaild(); + }; + + virtual bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) + { + m_output->SetResponseCode(responseCode); + // Expected response codes. + int expectedRespCode[1] = { 200, }; + bool isExpected = false; + for (int i = 0; i < 1; i++) + { + if (expectedRespCode[i] == responseCode) + { + isExpected = true; + break; + } + } + return isExpected; + }; + virtual void ParseResponseBody(std::iostream * responseBody); +}; + +void GetBucketPolicyUnparker::ParseResponseBody(std::iostream * responseBody) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(*responseBody, jsonContent); + if (jsonContent.isMember("statement")) + { + std::vector < StatementType > vecStatement; + for (unsigned i = 0; i < jsonContent["statement"].size(); ++i) + { + vecStatement.push_back(jsonContent["statement"][i]. + toStyledString()); + } + m_output->SetStatement(vecStatement); + } + m_bNeedReleaseBody = true; +} + +typedef QsDefaultRequestBuilder < GetBucketStatisticsInput > +GetBucketStatisticsBuilder; + +class GetBucketStatisticsUnparker:public QsDefaultResponseUnparker < + GetBucketStatisticsOutput > +{ +public: + GetBucketStatisticsUnparker(GetBucketStatisticsOutput * + output):QsDefaultResponseUnparker < + GetBucketStatisticsOutput > (output) + { + }; + + virtual ~ GetBucketStatisticsUnparker() + { + }; + + virtual bool CkeckIfOutputIsVaild() + { + return m_output->IsVaild(); + }; + + virtual bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) + { + m_output->SetResponseCode(responseCode); + // Expected response codes. + int expectedRespCode[1] = { 200, }; + bool isExpected = false; + for (int i = 0; i < 1; i++) + { + if (expectedRespCode[i] == responseCode) + { + isExpected = true; + break; + } + } + return isExpected; + }; + virtual void ParseResponseBody(std::iostream * responseBody); +}; + +void GetBucketStatisticsUnparker::ParseResponseBody(std::iostream * + responseBody) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(*responseBody, jsonContent); + if (jsonContent.isMember("count")) + { + m_output->SetCount(jsonContent["count"].asInt64()); + } + if (jsonContent.isMember("created")) + { + m_output->SetCreated(jsonContent["created"].asString()); + } + if (jsonContent.isMember("location")) + { + m_output->SetLocation(jsonContent["location"].asString()); + } + if (jsonContent.isMember("name")) + { + m_output->SetName(jsonContent["name"].asString()); + } + if (jsonContent.isMember("size")) + { + m_output->SetSize(jsonContent["size"].asInt64()); + } + if (jsonContent.isMember("status")) + { + m_output->SetStatus(jsonContent["status"].asString()); + } + if (jsonContent.isMember("url")) + { + m_output->SetURL(jsonContent["url"].asString()); + } + m_bNeedReleaseBody = true; +} + +typedef QsDefaultRequestBuilder < HeadBucketInput > HeadBucketBuilder; + +typedef QsDefaultResponseUnparker < HeadBucketOutput > HeadBucketUnparker; + +class ListMultipartUploadsBuilder:public QsDefaultRequestBuilder < + ListMultipartUploadsInput > +{ +public: + ListMultipartUploadsBuilder(ListMultipartUploadsInput * + input):QsDefaultRequestBuilder < + ListMultipartUploadsInput > (input) + { + }; + + virtual ~ ListMultipartUploadsBuilder() + { + }; + + virtual bool CkeckIfInputIsVaild() + { + return m_input->CheckIfInputIsVaild(); + }; + virtual Http::QueryParamCollection GetQueryParamCollection(); +}; + +// ListMultipartUploadsRequest AddQueryStringParameters. +Http::QueryParamCollection ListMultipartUploadsBuilder:: +GetQueryParamCollection() +{ + Http::QueryParamCollection queryParameters; + std::stringstream ss; + std::vector < std::string >::iterator it; + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_LIST_MULTIPART_UPLOADS_DELIMITER_FLAG)) + { + ss << m_input->GetDelimiter(); + queryParameters.insert(Http::HeaderValuePair("delimiter", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_LIST_MULTIPART_UPLOADS_KEY_MARKER_FLAG)) + { + ss << m_input->GetKeyMarker(); + queryParameters.insert(Http::HeaderValuePair("key_marker", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_LIST_MULTIPART_UPLOADS_LIMIT_FLAG)) + { + ss << m_input->GetLimit(); + queryParameters.insert(Http::HeaderValuePair("limit", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_LIST_MULTIPART_UPLOADS_PREFIX_FLAG)) + { + ss << m_input->GetPrefix(); + queryParameters.insert(Http::HeaderValuePair("prefix", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_LIST_MULTIPART_UPLOADS_UPLOAD_ID_MARKER_FLAG)) + { + ss << m_input->GetUploadIDMarker(); + queryParameters. + insert(Http::HeaderValuePair("upload_id_marker", ss.str())); + ss.str(""); + } + return queryParameters; +} + +class ListMultipartUploadsUnparker:public QsDefaultResponseUnparker < + ListMultipartUploadsOutput > +{ +public: + ListMultipartUploadsUnparker(ListMultipartUploadsOutput * + output):QsDefaultResponseUnparker < + ListMultipartUploadsOutput > (output) + { + }; + + virtual ~ ListMultipartUploadsUnparker() + { + }; + + virtual bool CkeckIfOutputIsVaild() + { + return m_output->IsVaild(); + }; + + virtual bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) + { + m_output->SetResponseCode(responseCode); + // Expected response codes. + int expectedRespCode[1] = { 200, }; + bool isExpected = false; + for (int i = 0; i < 1; i++) + { + if (expectedRespCode[i] == responseCode) + { + isExpected = true; + break; + } + } + return isExpected; + }; + virtual void ParseResponseBody(std::iostream * responseBody); +}; + +void ListMultipartUploadsUnparker::ParseResponseBody(std::iostream * + responseBody) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(*responseBody, jsonContent); + if (jsonContent.isMember("common_prefixes")) + { + std::vector < std::string > vecCommonPrefixes; + for (unsigned i = 0; i < jsonContent["common_prefixes"].size(); ++i) + { + vecCommonPrefixes.push_back(jsonContent["common_prefixes"][i]. + asString()); + } + m_output->SetCommonPrefixes(vecCommonPrefixes); + } + if (jsonContent.isMember("delimiter")) + { + m_output->SetDelimiter(jsonContent["delimiter"].asString()); + } + if (jsonContent.isMember("limit")) + { + m_output->SetLimit(jsonContent["limit"].asInt()); + } + if (jsonContent.isMember("marker")) + { + m_output->SetMarker(jsonContent["marker"].asString()); + } + if (jsonContent.isMember("name")) + { + m_output->SetName(jsonContent["name"].asString()); + } + if (jsonContent.isMember("next_key_marker")) + { + m_output->SetNextKeyMarker(jsonContent["next_key_marker"].asString()); + } + if (jsonContent.isMember("next_upload_id_marker")) + { + m_output->SetNextUploadIDMarker(jsonContent["next_upload_id_marker"]. + asString()); + } + if (jsonContent.isMember("prefix")) + { + m_output->SetPrefix(jsonContent["prefix"].asString()); + } + if (jsonContent.isMember("uploads")) + { + std::vector < UploadsType > vecUploads; + for (unsigned i = 0; i < jsonContent["uploads"].size(); ++i) + { + vecUploads.push_back(jsonContent["uploads"][i].toStyledString()); + } + m_output->SetUploads(vecUploads); + } + m_bNeedReleaseBody = true; +} + +class ListObjectsBuilder:public QsDefaultRequestBuilder < ListObjectsInput > +{ +public: + ListObjectsBuilder(ListObjectsInput * input):QsDefaultRequestBuilder < + ListObjectsInput > (input) + { + }; + + virtual ~ ListObjectsBuilder() + { + }; + + virtual bool CkeckIfInputIsVaild() + { + return m_input->CheckIfInputIsVaild(); + }; + virtual Http::QueryParamCollection GetQueryParamCollection(); +}; + +// ListObjectsRequest AddQueryStringParameters. +Http::QueryParamCollection ListObjectsBuilder::GetQueryParamCollection() +{ + Http::QueryParamCollection queryParameters; + std::stringstream ss; + std::vector < std::string >::iterator it; + if (m_input->IsPropHasBeenSet(SETTING_INPUT_LIST_OBJECTS_DELIMITER_FLAG)) + { + ss << m_input->GetDelimiter(); + queryParameters.insert(Http::HeaderValuePair("delimiter", ss.str())); + ss.str(""); + } + if (m_input->IsPropHasBeenSet(SETTING_INPUT_LIST_OBJECTS_LIMIT_FLAG)) + { + ss << m_input->GetLimit(); + queryParameters.insert(Http::HeaderValuePair("limit", ss.str())); + ss.str(""); + } + if (m_input->IsPropHasBeenSet(SETTING_INPUT_LIST_OBJECTS_MARKER_FLAG)) + { + ss << m_input->GetMarker(); + queryParameters.insert(Http::HeaderValuePair("marker", ss.str())); + ss.str(""); + } + if (m_input->IsPropHasBeenSet(SETTING_INPUT_LIST_OBJECTS_PREFIX_FLAG)) + { + ss << m_input->GetPrefix(); + queryParameters.insert(Http::HeaderValuePair("prefix", ss.str())); + ss.str(""); + } + return queryParameters; +} + +class ListObjectsUnparker:public QsDefaultResponseUnparker < ListObjectsOutput > +{ +public: + ListObjectsUnparker(ListObjectsOutput * output):QsDefaultResponseUnparker < + ListObjectsOutput > (output) + { + }; + + virtual ~ ListObjectsUnparker() + { + }; + + virtual bool CkeckIfOutputIsVaild() + { + return m_output->IsVaild(); + }; + + virtual bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) + { + m_output->SetResponseCode(responseCode); + // Expected response codes. + int expectedRespCode[1] = { 200, }; + bool isExpected = false; + for (int i = 0; i < 1; i++) + { + if (expectedRespCode[i] == responseCode) + { + isExpected = true; + break; + } + } + return isExpected; + }; + virtual void ParseResponseBody(std::iostream * responseBody); +}; + +void ListObjectsUnparker::ParseResponseBody(std::iostream * responseBody) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(*responseBody, jsonContent); + if (jsonContent.isMember("common_prefixes")) + { + std::vector < std::string > vecCommonPrefixes; + for (unsigned i = 0; i < jsonContent["common_prefixes"].size(); ++i) + { + vecCommonPrefixes.push_back(jsonContent["common_prefixes"][i]. + asString()); + } + m_output->SetCommonPrefixes(vecCommonPrefixes); + } + if (jsonContent.isMember("delimiter")) + { + m_output->SetDelimiter(jsonContent["delimiter"].asString()); + } + if (jsonContent.isMember("keys")) + { + std::vector < KeyType > vecKeys; + for (unsigned i = 0; i < jsonContent["keys"].size(); ++i) + { + vecKeys.push_back(jsonContent["keys"][i].toStyledString()); + } + m_output->SetKeys(vecKeys); + } + if (jsonContent.isMember("limit")) + { + m_output->SetLimit(jsonContent["limit"].asInt()); + } + if (jsonContent.isMember("marker")) + { + m_output->SetMarker(jsonContent["marker"].asString()); + } + if (jsonContent.isMember("name")) + { + m_output->SetName(jsonContent["name"].asString()); + } + if (jsonContent.isMember("next_marker")) + { + m_output->SetNextMarker(jsonContent["next_marker"].asString()); + } + if (jsonContent.isMember("owner")) + { + m_output->SetOwner(jsonContent["owner"].toStyledString()); + } + if (jsonContent.isMember("prefix")) + { + m_output->SetPrefix(jsonContent["prefix"].asString()); + } + m_bNeedReleaseBody = true; +} + +typedef QsDefaultRequestBuilder < PutBucketInput > PutBucketBuilder; + +typedef QsDefaultResponseUnparker < PutBucketOutput > PutBucketUnparker; + +class PutBucketACLBuilder:public QsDefaultRequestBuilder < PutBucketACLInput > +{ +public: + PutBucketACLBuilder(PutBucketACLInput * input):QsDefaultRequestBuilder < + PutBucketACLInput > (input) + { + }; + + virtual ~ PutBucketACLBuilder() + { + }; + + virtual bool CkeckIfInputIsVaild() + { + return m_input->CheckIfInputIsVaild(); + }; + virtual std::iostream * GetRequestBody(); +}; + +// PutBucketACLRequest GetRequestBody. +std::iostream * PutBucketACLBuilder::GetRequestBody() +{ + //TO DO; + Json::FastWriter jsonWriter; + Json::Value jsonContent; + if (m_input->IsPropHasBeenSet(SETTING_INPUT_PUT_BUCKET_ACL_ACL_FLAG)) + { + Json::Value arrayACL; + std::vector < ACLType > acl = m_input->GetACL(); + for (std::vector < ACLType >::iterator it = acl.begin(); + it != acl.end(); it++) + { + Json::Reader jsonReader; + Json::Value itemJsonValue; + jsonReader.parse(it->Serialize(), itemJsonValue); + arrayACL.append(itemJsonValue); + } + jsonContent["acl"] = arrayACL; + } + m_bNeedReleaseBody = true; + return new std::stringstream(jsonWriter.write(jsonContent)); +} + +typedef QsDefaultResponseUnparker < PutBucketACLOutput > PutBucketACLUnparker; + +class PutBucketCORSBuilder:public QsDefaultRequestBuilder < PutBucketCORSInput > +{ +public: + PutBucketCORSBuilder(PutBucketCORSInput * input):QsDefaultRequestBuilder < + PutBucketCORSInput > (input) + { + }; + + virtual ~ PutBucketCORSBuilder() + { + }; + + virtual bool CkeckIfInputIsVaild() + { + return m_input->CheckIfInputIsVaild(); + }; + virtual std::iostream * GetRequestBody(); +}; + +// PutBucketCORSRequest GetRequestBody. +std::iostream * PutBucketCORSBuilder::GetRequestBody() +{ + //TO DO; + Json::FastWriter jsonWriter; + Json::Value jsonContent; + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_PUT_BUCKET_CORS_CORS_RULES_FLAG)) + { + Json::Value arrayCORSRules; + std::vector < CORSRuleType > corsRules = m_input->GetCORSRules(); + for (std::vector < CORSRuleType >::iterator it = corsRules.begin(); + it != corsRules.end(); it++) + { + Json::Reader jsonReader; + Json::Value itemJsonValue; + jsonReader.parse(it->Serialize(), itemJsonValue); + arrayCORSRules.append(itemJsonValue); + } + jsonContent["cors_rules"] = arrayCORSRules; + } + m_bNeedReleaseBody = true; + return new std::stringstream(jsonWriter.write(jsonContent)); +} + +typedef QsDefaultResponseUnparker < PutBucketCORSOutput > PutBucketCORSUnparker; + +class PutBucketExternalMirrorBuilder:public QsDefaultRequestBuilder < + PutBucketExternalMirrorInput > +{ +public: + PutBucketExternalMirrorBuilder(PutBucketExternalMirrorInput * + input):QsDefaultRequestBuilder < + PutBucketExternalMirrorInput > (input) + { + }; + + virtual ~ PutBucketExternalMirrorBuilder() + { + }; + + virtual bool CkeckIfInputIsVaild() + { + return m_input->CheckIfInputIsVaild(); + }; + virtual std::iostream * GetRequestBody(); +}; + +// PutBucketExternalMirrorRequest GetRequestBody. +std::iostream * PutBucketExternalMirrorBuilder::GetRequestBody() +{ + //TO DO; + Json::FastWriter jsonWriter; + Json::Value jsonContent; + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_PUT_BUCKET_EXTERNAL_MIRROR_SOURCE_SITE_FLAG)) + { + jsonContent["source_site"] = m_input->GetSourceSite(); + } + m_bNeedReleaseBody = true; + return new std::stringstream(jsonWriter.write(jsonContent)); +} + +typedef QsDefaultResponseUnparker < PutBucketExternalMirrorOutput > +PutBucketExternalMirrorUnparker; + +class PutBucketPolicyBuilder:public QsDefaultRequestBuilder < + PutBucketPolicyInput > +{ +public: + PutBucketPolicyBuilder(PutBucketPolicyInput * + input):QsDefaultRequestBuilder < + PutBucketPolicyInput > (input) + { + }; + + virtual ~ PutBucketPolicyBuilder() + { + }; + + virtual bool CkeckIfInputIsVaild() + { + return m_input->CheckIfInputIsVaild(); + }; + virtual std::iostream * GetRequestBody(); +}; + +// PutBucketPolicyRequest GetRequestBody. +std::iostream * PutBucketPolicyBuilder::GetRequestBody() +{ + //TO DO; + Json::FastWriter jsonWriter; + Json::Value jsonContent; + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_PUT_BUCKET_POLICY_STATEMENT_FLAG)) + { + Json::Value arrayStatement; + std::vector < StatementType > statement = m_input->GetStatement(); + for (std::vector < StatementType >::iterator it = statement.begin(); + it != statement.end(); it++) + { + Json::Reader jsonReader; + Json::Value itemJsonValue; + jsonReader.parse(it->Serialize(), itemJsonValue); + arrayStatement.append(itemJsonValue); + } + jsonContent["statement"] = arrayStatement; + } + m_bNeedReleaseBody = true; + return new std::stringstream(jsonWriter.write(jsonContent)); +} + +typedef QsDefaultResponseUnparker < PutBucketPolicyOutput > +PutBucketPolicyUnparker; + +// +-------------------------------------------------------------------- +// | RequestBuilderSource and ResponseUnparkerSource +// +-------------------------------------------------------------------- +class AbortMultipartUploadBuilder:public QsDefaultRequestBuilder < + AbortMultipartUploadInput > +{ +public: + AbortMultipartUploadBuilder(AbortMultipartUploadInput * + input):QsDefaultRequestBuilder < + AbortMultipartUploadInput > (input) + { + }; + + virtual ~ AbortMultipartUploadBuilder() + { + }; + + virtual bool CkeckIfInputIsVaild() + { + return m_input->CheckIfInputIsVaild(); + }; + virtual Http::QueryParamCollection GetQueryParamCollection(); +}; + +// AbortMultipartUploadRequest AddQueryStringParameters. +Http::QueryParamCollection AbortMultipartUploadBuilder:: +GetQueryParamCollection() +{ + Http::QueryParamCollection queryParameters; + std::stringstream ss; + std::vector < std::string >::iterator it; + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_ABORT_MULTIPART_UPLOAD_UPLOAD_ID_FLAG)) + { + ss << m_input->GetUploadID(); + queryParameters.insert(Http::HeaderValuePair("upload_id", ss.str())); + ss.str(""); + } + return queryParameters; +} + +typedef QsDefaultResponseUnparker < AbortMultipartUploadOutput > +AbortMultipartUploadUnparker; + +class CompleteMultipartUploadBuilder:public QsDefaultRequestBuilder < + CompleteMultipartUploadInput > +{ +public: + CompleteMultipartUploadBuilder(CompleteMultipartUploadInput * + input):QsDefaultRequestBuilder < + CompleteMultipartUploadInput > (input) + { + }; + + virtual ~ CompleteMultipartUploadBuilder() + { + }; + + virtual bool CkeckIfInputIsVaild() + { + return m_input->CheckIfInputIsVaild(); + }; + virtual Http::HeaderValueCollection GetHeaderValueCollection(); + virtual Http::QueryParamCollection GetQueryParamCollection(); + virtual std::iostream * GetRequestBody(); +}; + +// CompleteMultipartUploadRequest GetRequestSpecificHeaders. +Http::HeaderValueCollection CompleteMultipartUploadBuilder:: +GetHeaderValueCollection() +{ + //TO DO; + Http::HeaderValueCollection headers; + std::stringstream ss; + std::vector < std::string >::iterator it; + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_COMPLETE_MULTIPART_UPLOAD_ETAG_FLAG)) + { + ss << m_input->GetETag(); + headers.insert(Http::HeaderValuePair("ETag", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_COMPLETE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG)) + { + ss << m_input->GetXQSEncryptionCustomerAlgorithm(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Encryption-Customer-Algorithm", + ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_COMPLETE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_KEY_FLAG)) + { + ss << m_input->GetXQSEncryptionCustomerKey(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Encryption-Customer-Key", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_COMPLETE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG)) + { + ss << m_input->GetXQSEncryptionCustomerKeyMD5(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Encryption-Customer-Key-MD5", + ss.str())); + ss.str(""); + } + return headers; +} + +// CompleteMultipartUploadRequest AddQueryStringParameters. +Http::QueryParamCollection CompleteMultipartUploadBuilder:: +GetQueryParamCollection() +{ + Http::QueryParamCollection queryParameters; + std::stringstream ss; + std::vector < std::string >::iterator it; + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_COMPLETE_MULTIPART_UPLOAD_UPLOAD_ID_FLAG)) + { + ss << m_input->GetUploadID(); + queryParameters.insert(Http::HeaderValuePair("upload_id", ss.str())); + ss.str(""); + } + return queryParameters; +} + +// CompleteMultipartUploadRequest GetRequestBody. +std::iostream * CompleteMultipartUploadBuilder::GetRequestBody() +{ + //TO DO; + Json::FastWriter jsonWriter; + Json::Value jsonContent; + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_COMPLETE_MULTIPART_UPLOAD_OBJECT_PARTS_FLAG)) + { + Json::Value arrayObjectParts; + std::vector < ObjectPartType > objectParts = m_input->GetObjectParts(); + for (std::vector < ObjectPartType >::iterator it = objectParts.begin(); + it != objectParts.end(); it++) + { + Json::Reader jsonReader; + Json::Value itemJsonValue; + jsonReader.parse(it->Serialize(), itemJsonValue); + arrayObjectParts.append(itemJsonValue); + } + jsonContent["object_parts"] = arrayObjectParts; + } + m_bNeedReleaseBody = true; + return new std::stringstream(jsonWriter.write(jsonContent)); +} + +class CompleteMultipartUploadUnparker:public QsDefaultResponseUnparker < + CompleteMultipartUploadOutput > +{ +public: + CompleteMultipartUploadUnparker(CompleteMultipartUploadOutput * + output):QsDefaultResponseUnparker < + CompleteMultipartUploadOutput > (output) + { + }; + + virtual ~ CompleteMultipartUploadUnparker() + { + }; + + virtual bool CkeckIfOutputIsVaild() + { + return m_output->IsVaild(); + }; + + virtual bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) + { + m_output->SetResponseCode(responseCode); + // Expected response codes. + int expectedRespCode[1] = { 201, }; + bool isExpected = false; + for (int i = 0; i < 1; i++) + { + if (expectedRespCode[i] == responseCode) + { + isExpected = true; + break; + } + } + return isExpected; + }; + virtual void ParseResponseHeaders(const Http:: + HeaderValueCollection & + headerValueCollection); +}; + +// CompleteMultipartUploadRequest ParseResponseHeaders. +void CompleteMultipartUploadUnparker::ParseResponseHeaders(const Http:: + HeaderValueCollection + & + headerValueCollection) +{ + const HeaderValueCollection & headers = headerValueCollection; + HeaderValueCollection::const_iterator XQSEncryptionCustomerAlgorithmIter = + headers.find("x-qs-encryption-customer-algorithm"); + if (XQSEncryptionCustomerAlgorithmIter != headers.end()) + { + m_output-> + SetXQSEncryptionCustomerAlgorithm + (XQSEncryptionCustomerAlgorithmIter->second); + } +} + +typedef QsDefaultRequestBuilder < DeleteObjectInput > DeleteObjectBuilder; + +typedef QsDefaultResponseUnparker < DeleteObjectOutput > DeleteObjectUnparker; + +class GetObjectBuilder:public QsDefaultRequestBuilder < GetObjectInput > +{ +public: + GetObjectBuilder(GetObjectInput * input):QsDefaultRequestBuilder < + GetObjectInput > (input) + { + }; + + virtual ~ GetObjectBuilder() + { + }; + + virtual bool CkeckIfInputIsVaild() + { + return m_input->CheckIfInputIsVaild(); + }; + virtual Http::HeaderValueCollection GetHeaderValueCollection(); + virtual Http::QueryParamCollection GetQueryParamCollection(); +}; + +// GetObjectRequest GetRequestSpecificHeaders. +Http::HeaderValueCollection GetObjectBuilder::GetHeaderValueCollection() +{ + //TO DO; + Http::HeaderValueCollection headers; + std::stringstream ss; + std::vector < std::string >::iterator it; + if (m_input->IsPropHasBeenSet(SETTING_INPUT_GET_OBJECT_IF_MATCH_FLAG)) + { + ss << m_input->GetIfMatch(); + headers.insert(Http::HeaderValuePair("If-Match", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_GET_OBJECT_IF_MODIFIED_SINCE_FLAG)) + { + ss << m_input->GetIfModifiedSince(); + headers.insert(Http::HeaderValuePair("If-Modified-Since", ss.str())); + ss.str(""); + } + if (m_input->IsPropHasBeenSet(SETTING_INPUT_GET_OBJECT_IF_NONE_MATCH_FLAG)) + { + ss << m_input->GetIfNoneMatch(); + headers.insert(Http::HeaderValuePair("If-None-Match", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_GET_OBJECT_IF_UNMODIFIED_SINCE_FLAG)) + { + ss << m_input->GetIfUnmodifiedSince(); + headers.insert(Http::HeaderValuePair("If-Unmodified-Since", ss.str())); + ss.str(""); + } + if (m_input->IsPropHasBeenSet(SETTING_INPUT_GET_OBJECT_RANGE_FLAG)) + { + ss << m_input->GetRange(); + headers.insert(Http::HeaderValuePair("Range", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_GET_OBJECT_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG)) + { + ss << m_input->GetXQSEncryptionCustomerAlgorithm(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Encryption-Customer-Algorithm", + ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_GET_OBJECT_X_QS_ENCRYPTION_CUSTOMER_KEY_FLAG)) + { + ss << m_input->GetXQSEncryptionCustomerKey(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Encryption-Customer-Key", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_GET_OBJECT_X_QS_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG)) + { + ss << m_input->GetXQSEncryptionCustomerKeyMD5(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Encryption-Customer-Key-MD5", + ss.str())); + ss.str(""); + } + return headers; +} + +// GetObjectRequest AddQueryStringParameters. +Http::QueryParamCollection GetObjectBuilder::GetQueryParamCollection() +{ + Http::QueryParamCollection queryParameters; + std::stringstream ss; + std::vector < std::string >::iterator it; + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_GET_OBJECT_RESPONSE_CACHE_CONTROL_FLAG)) + { + ss << m_input->GetResponseCacheControl(); + queryParameters. + insert(Http::HeaderValuePair("response-cache-control", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_GET_OBJECT_RESPONSE_CONTENT_DISPOSITION_FLAG)) + { + ss << m_input->GetResponseContentDisposition(); + queryParameters. + insert(Http:: + HeaderValuePair("response-content-disposition", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_GET_OBJECT_RESPONSE_CONTENT_ENCODING_FLAG)) + { + ss << m_input->GetResponseContentEncoding(); + queryParameters. + insert(Http:: + HeaderValuePair("response-content-encoding", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_GET_OBJECT_RESPONSE_CONTENT_LANGUAGE_FLAG)) + { + ss << m_input->GetResponseContentLanguage(); + queryParameters. + insert(Http:: + HeaderValuePair("response-content-language", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_GET_OBJECT_RESPONSE_CONTENT_TYPE_FLAG)) + { + ss << m_input->GetResponseContentType(); + queryParameters. + insert(Http::HeaderValuePair("response-content-type", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_GET_OBJECT_RESPONSE_EXPIRES_FLAG)) + { + ss << m_input->GetResponseExpires(); + queryParameters. + insert(Http::HeaderValuePair("response-expires", ss.str())); + ss.str(""); + } + return queryParameters; +} + +class GetObjectUnparker:public QsDefaultResponseUnparker < GetObjectOutput > +{ +public: + GetObjectUnparker(GetObjectOutput * output):QsDefaultResponseUnparker < + GetObjectOutput > (output) + { + }; + + virtual ~ GetObjectUnparker() + { + }; + + virtual bool CkeckIfOutputIsVaild() + { + return m_output->IsVaild(); + }; + + virtual bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) + { + m_output->SetResponseCode(responseCode); + // Expected response codes. + int expectedRespCode[4] = { 200, 206, 304, 412, }; + bool isExpected = false; + for (int i = 0; i < 4; i++) + { + if (expectedRespCode[i] == responseCode) + { + isExpected = true; + break; + } + } + return isExpected; + }; + virtual void ParseResponseHeaders(const Http:: + HeaderValueCollection & + headerValueCollection); + virtual void ParseResponseBody(std::iostream * responseBody); + +}; + +// GetObjectRequest ParseResponseHeaders. +void GetObjectUnparker::ParseResponseHeaders(const Http:: + HeaderValueCollection & + headerValueCollection) +{ + const HeaderValueCollection & headers = headerValueCollection; + HeaderValueCollection::const_iterator CacheControlIter = + headers.find("cache-control"); + if (CacheControlIter != headers.end()) + { + m_output->SetCacheControl(CacheControlIter->second); + } + HeaderValueCollection::const_iterator ContentDispositionIter = + headers.find("content-disposition"); + if (ContentDispositionIter != headers.end()) + { + m_output->SetContentDisposition(ContentDispositionIter->second); + } + HeaderValueCollection::const_iterator ContentEncodingIter = + headers.find("content-encoding"); + if (ContentEncodingIter != headers.end()) + { + m_output->SetContentEncoding(ContentEncodingIter->second); + } + HeaderValueCollection::const_iterator ContentLanguageIter = + headers.find("content-language"); + if (ContentLanguageIter != headers.end()) + { + m_output->SetContentLanguage(ContentLanguageIter->second); + } + HeaderValueCollection::const_iterator ContentLengthIter = + headers.find("content-length"); + if (ContentLengthIter != headers.end()) + { + m_output-> + SetContentLength(StringUtils:: + ConvertToInt64(ContentLengthIter->second.c_str())); + } + HeaderValueCollection::const_iterator ContentRangeIter = + headers.find("content-range"); + if (ContentRangeIter != headers.end()) + { + m_output->SetContentRange(ContentRangeIter->second); + } + HeaderValueCollection::const_iterator ContentTypeIter = + headers.find("content-type"); + if (ContentTypeIter != headers.end()) + { + m_output->SetContentType(ContentTypeIter->second); + } + HeaderValueCollection::const_iterator ETagIter = headers.find("etag"); + if (ETagIter != headers.end()) + { + m_output->SetETag(ETagIter->second); + } + HeaderValueCollection::const_iterator ExpiresIter = headers.find("expires"); + if (ExpiresIter != headers.end()) + { + m_output->SetExpires(ExpiresIter->second); + } + HeaderValueCollection::const_iterator LastModifiedIter = + headers.find("last-modified"); + if (LastModifiedIter != headers.end()) + { + m_output->SetLastModified(LastModifiedIter->second); + } + HeaderValueCollection::const_iterator XQSEncryptionCustomerAlgorithmIter = + headers.find("x-qs-encryption-customer-algorithm"); + if (XQSEncryptionCustomerAlgorithmIter != headers.end()) + { + m_output-> + SetXQSEncryptionCustomerAlgorithm + (XQSEncryptionCustomerAlgorithmIter->second); + } +} + +void GetObjectUnparker::ParseResponseBody(std::iostream * responseBody) +{ + m_output->SetBody(responseBody); +} + +class HeadObjectBuilder:public QsDefaultRequestBuilder < HeadObjectInput > +{ +public: + HeadObjectBuilder(HeadObjectInput * input):QsDefaultRequestBuilder < + HeadObjectInput > (input) + { + }; + + virtual ~ HeadObjectBuilder() + { + }; + + virtual bool CkeckIfInputIsVaild() + { + return m_input->CheckIfInputIsVaild(); + }; + virtual Http::HeaderValueCollection GetHeaderValueCollection(); +}; + +// HeadObjectRequest GetRequestSpecificHeaders. +Http::HeaderValueCollection HeadObjectBuilder::GetHeaderValueCollection() +{ + //TO DO; + Http::HeaderValueCollection headers; + std::stringstream ss; + std::vector < std::string >::iterator it; + if (m_input->IsPropHasBeenSet(SETTING_INPUT_HEAD_OBJECT_IF_MATCH_FLAG)) + { + ss << m_input->GetIfMatch(); + headers.insert(Http::HeaderValuePair("If-Match", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_HEAD_OBJECT_IF_MODIFIED_SINCE_FLAG)) + { + ss << m_input->GetIfModifiedSince(); + headers.insert(Http::HeaderValuePair("If-Modified-Since", ss.str())); + ss.str(""); + } + if (m_input->IsPropHasBeenSet(SETTING_INPUT_HEAD_OBJECT_IF_NONE_MATCH_FLAG)) + { + ss << m_input->GetIfNoneMatch(); + headers.insert(Http::HeaderValuePair("If-None-Match", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_HEAD_OBJECT_IF_UNMODIFIED_SINCE_FLAG)) + { + ss << m_input->GetIfUnmodifiedSince(); + headers.insert(Http::HeaderValuePair("If-Unmodified-Since", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_HEAD_OBJECT_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG)) + { + ss << m_input->GetXQSEncryptionCustomerAlgorithm(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Encryption-Customer-Algorithm", + ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_HEAD_OBJECT_X_QS_ENCRYPTION_CUSTOMER_KEY_FLAG)) + { + ss << m_input->GetXQSEncryptionCustomerKey(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Encryption-Customer-Key", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_HEAD_OBJECT_X_QS_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG)) + { + ss << m_input->GetXQSEncryptionCustomerKeyMD5(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Encryption-Customer-Key-MD5", + ss.str())); + ss.str(""); + } + return headers; +} + +class HeadObjectUnparker:public QsDefaultResponseUnparker < HeadObjectOutput > +{ +public: + HeadObjectUnparker(HeadObjectOutput * output):QsDefaultResponseUnparker < + HeadObjectOutput > (output) + { + }; + + virtual ~ HeadObjectUnparker() + { + }; + + virtual bool CkeckIfOutputIsVaild() + { + return m_output->IsVaild(); + }; + + virtual bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) + { + m_output->SetResponseCode(responseCode); + // Expected response codes. + int expectedRespCode[1] = { 200, }; + bool isExpected = false; + for (int i = 0; i < 1; i++) + { + if (expectedRespCode[i] == responseCode) + { + isExpected = true; + break; + } + } + return isExpected; + }; + virtual void ParseResponseHeaders(const Http:: + HeaderValueCollection & + headerValueCollection); +}; + +// HeadObjectRequest ParseResponseHeaders. +void HeadObjectUnparker::ParseResponseHeaders(const Http:: + HeaderValueCollection & + headerValueCollection) +{ + const HeaderValueCollection & headers = headerValueCollection; + HeaderValueCollection::const_iterator ContentLengthIter = + headers.find("content-length"); + if (ContentLengthIter != headers.end()) + { + m_output-> + SetContentLength(StringUtils:: + ConvertToInt64(ContentLengthIter->second.c_str())); + } + HeaderValueCollection::const_iterator ContentTypeIter = + headers.find("content-type"); + if (ContentTypeIter != headers.end()) + { + m_output->SetContentType(ContentTypeIter->second); + } + HeaderValueCollection::const_iterator ETagIter = headers.find("etag"); + if (ETagIter != headers.end()) + { + m_output->SetETag(ETagIter->second); + } + HeaderValueCollection::const_iterator LastModifiedIter = + headers.find("last-modified"); + if (LastModifiedIter != headers.end()) + { + m_output->SetLastModified(LastModifiedIter->second); + } + HeaderValueCollection::const_iterator XQSEncryptionCustomerAlgorithmIter = + headers.find("x-qs-encryption-customer-algorithm"); + if (XQSEncryptionCustomerAlgorithmIter != headers.end()) + { + m_output-> + SetXQSEncryptionCustomerAlgorithm + (XQSEncryptionCustomerAlgorithmIter->second); + } +} + +class ImageProcessBuilder:public QsDefaultRequestBuilder < ImageProcessInput > +{ +public: + ImageProcessBuilder(ImageProcessInput * input):QsDefaultRequestBuilder < + ImageProcessInput > (input) + { + }; + + virtual ~ ImageProcessBuilder() + { + }; + + virtual bool CkeckIfInputIsVaild() + { + return m_input->CheckIfInputIsVaild(); + }; + virtual Http::HeaderValueCollection GetHeaderValueCollection(); + virtual Http::QueryParamCollection GetQueryParamCollection(); +}; + +// ImageProcessRequest GetRequestSpecificHeaders. +Http::HeaderValueCollection ImageProcessBuilder::GetHeaderValueCollection() +{ + //TO DO; + Http::HeaderValueCollection headers; + std::stringstream ss; + std::vector < std::string >::iterator it; + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_IMAGE_PROCESS_IF_MODIFIED_SINCE_FLAG)) + { + ss << m_input->GetIfModifiedSince(); + headers.insert(Http::HeaderValuePair("If-Modified-Since", ss.str())); + ss.str(""); + } + return headers; +} + +// ImageProcessRequest AddQueryStringParameters. +Http::QueryParamCollection ImageProcessBuilder::GetQueryParamCollection() +{ + Http::QueryParamCollection queryParameters; + std::stringstream ss; + std::vector < std::string >::iterator it; + if (m_input->IsPropHasBeenSet(SETTING_INPUT_IMAGE_PROCESS_ACTION_FLAG)) + { + ss << m_input->GetAction(); + queryParameters.insert(Http::HeaderValuePair("action", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_IMAGE_PROCESS_RESPONSE_CACHE_CONTROL_FLAG)) + { + ss << m_input->GetResponseCacheControl(); + queryParameters. + insert(Http::HeaderValuePair("response-cache-control", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_IMAGE_PROCESS_RESPONSE_CONTENT_DISPOSITION_FLAG)) + { + ss << m_input->GetResponseContentDisposition(); + queryParameters. + insert(Http:: + HeaderValuePair("response-content-disposition", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_IMAGE_PROCESS_RESPONSE_CONTENT_ENCODING_FLAG)) + { + ss << m_input->GetResponseContentEncoding(); + queryParameters. + insert(Http:: + HeaderValuePair("response-content-encoding", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_IMAGE_PROCESS_RESPONSE_CONTENT_LANGUAGE_FLAG)) + { + ss << m_input->GetResponseContentLanguage(); + queryParameters. + insert(Http:: + HeaderValuePair("response-content-language", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_IMAGE_PROCESS_RESPONSE_CONTENT_TYPE_FLAG)) + { + ss << m_input->GetResponseContentType(); + queryParameters. + insert(Http::HeaderValuePair("response-content-type", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_IMAGE_PROCESS_RESPONSE_EXPIRES_FLAG)) + { + ss << m_input->GetResponseExpires(); + queryParameters. + insert(Http::HeaderValuePair("response-expires", ss.str())); + ss.str(""); + } + return queryParameters; +} + +class ImageProcessUnparker:public QsDefaultResponseUnparker < + ImageProcessOutput > +{ +public: + ImageProcessUnparker(ImageProcessOutput * + output):QsDefaultResponseUnparker < + ImageProcessOutput > (output) + { + }; + + virtual ~ ImageProcessUnparker() + { + }; + + virtual bool CkeckIfOutputIsVaild() + { + return m_output->IsVaild(); + }; + + virtual bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) + { + m_output->SetResponseCode(responseCode); + // Expected response codes. + int expectedRespCode[2] = { 200, 304, }; + bool isExpected = false; + for (int i = 0; i < 2; i++) + { + if (expectedRespCode[i] == responseCode) + { + isExpected = true; + break; + } + } + return isExpected; + }; + virtual void ParseResponseHeaders(const Http:: + HeaderValueCollection & + headerValueCollection); + virtual void ParseResponseBody(std::iostream * responseBody); + +}; + +// ImageProcessRequest ParseResponseHeaders. +void ImageProcessUnparker::ParseResponseHeaders(const Http:: + HeaderValueCollection & + headerValueCollection) +{ + const HeaderValueCollection & headers = headerValueCollection; + HeaderValueCollection::const_iterator ContentLengthIter = + headers.find("content-length"); + if (ContentLengthIter != headers.end()) + { + m_output-> + SetContentLength(StringUtils:: + ConvertToInt64(ContentLengthIter->second.c_str())); + } +} + +void ImageProcessUnparker::ParseResponseBody(std::iostream * responseBody) +{ + m_output->SetBody(responseBody); +} + +class InitiateMultipartUploadBuilder:public QsDefaultRequestBuilder < + InitiateMultipartUploadInput > +{ +public: + InitiateMultipartUploadBuilder(InitiateMultipartUploadInput * + input):QsDefaultRequestBuilder < + InitiateMultipartUploadInput > (input) + { + }; + + virtual ~ InitiateMultipartUploadBuilder() + { + }; + + virtual bool CkeckIfInputIsVaild() + { + return m_input->CheckIfInputIsVaild(); + }; + virtual Http::HeaderValueCollection GetHeaderValueCollection(); +}; + +// InitiateMultipartUploadRequest GetRequestSpecificHeaders. +Http::HeaderValueCollection InitiateMultipartUploadBuilder:: +GetHeaderValueCollection() +{ + //TO DO; + Http::HeaderValueCollection headers; + std::stringstream ss; + std::vector < std::string >::iterator it; + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_INITIATE_MULTIPART_UPLOAD_CONTENT_TYPE_FLAG)) + { + ss << m_input->GetContentType(); + headers.insert(Http::HeaderValuePair("Content-Type", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_INITIATE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG)) + { + ss << m_input->GetXQSEncryptionCustomerAlgorithm(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Encryption-Customer-Algorithm", + ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_INITIATE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_KEY_FLAG)) + { + ss << m_input->GetXQSEncryptionCustomerKey(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Encryption-Customer-Key", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_INITIATE_MULTIPART_UPLOAD_X_QS_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG)) + { + ss << m_input->GetXQSEncryptionCustomerKeyMD5(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Encryption-Customer-Key-MD5", + ss.str())); + ss.str(""); + } + return headers; +} + +class InitiateMultipartUploadUnparker:public QsDefaultResponseUnparker < + InitiateMultipartUploadOutput > +{ +public: + InitiateMultipartUploadUnparker(InitiateMultipartUploadOutput * + output):QsDefaultResponseUnparker < + InitiateMultipartUploadOutput > (output) + { + }; + + virtual ~ InitiateMultipartUploadUnparker() + { + }; + + virtual bool CkeckIfOutputIsVaild() + { + return m_output->IsVaild(); + }; + + virtual bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) + { + m_output->SetResponseCode(responseCode); + // Expected response codes. + int expectedRespCode[1] = { 200, }; + bool isExpected = false; + for (int i = 0; i < 1; i++) + { + if (expectedRespCode[i] == responseCode) + { + isExpected = true; + break; + } + } + return isExpected; + }; + virtual void ParseResponseHeaders(const Http:: + HeaderValueCollection & + headerValueCollection); + virtual void ParseResponseBody(std::iostream * responseBody); +}; + +// InitiateMultipartUploadRequest ParseResponseHeaders. +void InitiateMultipartUploadUnparker::ParseResponseHeaders(const Http:: + HeaderValueCollection + & + headerValueCollection) +{ + const HeaderValueCollection & headers = headerValueCollection; + HeaderValueCollection::const_iterator XQSEncryptionCustomerAlgorithmIter = + headers.find("x-qs-encryption-customer-algorithm"); + if (XQSEncryptionCustomerAlgorithmIter != headers.end()) + { + m_output-> + SetXQSEncryptionCustomerAlgorithm + (XQSEncryptionCustomerAlgorithmIter->second); + } +} + +void InitiateMultipartUploadUnparker::ParseResponseBody(std::iostream * + responseBody) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(*responseBody, jsonContent); + if (jsonContent.isMember("bucket")) + { + m_output->SetBucket(jsonContent["bucket"].asString()); + } + if (jsonContent.isMember("key")) + { + m_output->SetKey(jsonContent["key"].asString()); + } + if (jsonContent.isMember("upload_id")) + { + m_output->SetUploadID(jsonContent["upload_id"].asString()); + } + m_bNeedReleaseBody = true; +} + +class ListMultipartBuilder:public QsDefaultRequestBuilder < ListMultipartInput > +{ +public: + ListMultipartBuilder(ListMultipartInput * input):QsDefaultRequestBuilder < + ListMultipartInput > (input) + { + }; + + virtual ~ ListMultipartBuilder() + { + }; + + virtual bool CkeckIfInputIsVaild() + { + return m_input->CheckIfInputIsVaild(); + }; + virtual Http::QueryParamCollection GetQueryParamCollection(); +}; + +// ListMultipartRequest AddQueryStringParameters. +Http::QueryParamCollection ListMultipartBuilder::GetQueryParamCollection() +{ + Http::QueryParamCollection queryParameters; + std::stringstream ss; + std::vector < std::string >::iterator it; + if (m_input->IsPropHasBeenSet(SETTING_INPUT_LIST_MULTIPART_LIMIT_FLAG)) + { + ss << m_input->GetLimit(); + queryParameters.insert(Http::HeaderValuePair("limit", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_LIST_MULTIPART_PART_NUMBER_MARKER_FLAG)) + { + ss << m_input->GetPartNumberMarker(); + queryParameters. + insert(Http::HeaderValuePair("part_number_marker", ss.str())); + ss.str(""); + } + if (m_input->IsPropHasBeenSet(SETTING_INPUT_LIST_MULTIPART_UPLOAD_ID_FLAG)) + { + ss << m_input->GetUploadID(); + queryParameters.insert(Http::HeaderValuePair("upload_id", ss.str())); + ss.str(""); + } + return queryParameters; +} + +class ListMultipartUnparker:public QsDefaultResponseUnparker < + ListMultipartOutput > +{ +public: + ListMultipartUnparker(ListMultipartOutput * + output):QsDefaultResponseUnparker < + ListMultipartOutput > (output) + { + }; + + virtual ~ ListMultipartUnparker() + { + }; + + virtual bool CkeckIfOutputIsVaild() + { + return m_output->IsVaild(); + }; + + virtual bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) + { + m_output->SetResponseCode(responseCode); + // Expected response codes. + int expectedRespCode[1] = { 200, }; + bool isExpected = false; + for (int i = 0; i < 1; i++) + { + if (expectedRespCode[i] == responseCode) + { + isExpected = true; + break; + } + } + return isExpected; + }; + virtual void ParseResponseBody(std::iostream * responseBody); +}; + +void ListMultipartUnparker::ParseResponseBody(std::iostream * responseBody) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(*responseBody, jsonContent); + if (jsonContent.isMember("count")) + { + m_output->SetCount(jsonContent["count"].asInt()); + } + if (jsonContent.isMember("object_parts")) + { + std::vector < ObjectPartType > vecObjectParts; + for (unsigned i = 0; i < jsonContent["object_parts"].size(); ++i) + { + vecObjectParts.push_back(jsonContent["object_parts"][i]. + toStyledString()); + } + m_output->SetObjectParts(vecObjectParts); + } + m_bNeedReleaseBody = true; +} + +class OptionsObjectBuilder:public QsDefaultRequestBuilder < OptionsObjectInput > +{ +public: + OptionsObjectBuilder(OptionsObjectInput * input):QsDefaultRequestBuilder < + OptionsObjectInput > (input) + { + }; + + virtual ~ OptionsObjectBuilder() + { + }; + + virtual bool CkeckIfInputIsVaild() + { + return m_input->CheckIfInputIsVaild(); + }; + virtual Http::HeaderValueCollection GetHeaderValueCollection(); +}; + +// OptionsObjectRequest GetRequestSpecificHeaders. +Http::HeaderValueCollection OptionsObjectBuilder::GetHeaderValueCollection() +{ + //TO DO; + Http::HeaderValueCollection headers; + std::stringstream ss; + std::vector < std::string >::iterator it; + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_OPTIONS_OBJECT_ACCESS_CONTROL_REQUEST_HEADERS_FLAG)) + { + ss << m_input->GetAccessControlRequestHeaders(); + headers. + insert(Http:: + HeaderValuePair("Access-Control-Request-Headers", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_OPTIONS_OBJECT_ACCESS_CONTROL_REQUEST_METHOD_FLAG)) + { + ss << m_input->GetAccessControlRequestMethod(); + headers. + insert(Http:: + HeaderValuePair("Access-Control-Request-Method", ss.str())); + ss.str(""); + } + if (m_input->IsPropHasBeenSet(SETTING_INPUT_OPTIONS_OBJECT_ORIGIN_FLAG)) + { + ss << m_input->GetOrigin(); + headers.insert(Http::HeaderValuePair("Origin", ss.str())); + ss.str(""); + } + return headers; +} + +class OptionsObjectUnparker:public QsDefaultResponseUnparker < + OptionsObjectOutput > +{ +public: + OptionsObjectUnparker(OptionsObjectOutput * + output):QsDefaultResponseUnparker < + OptionsObjectOutput > (output) + { + }; + + virtual ~ OptionsObjectUnparker() + { + }; + + virtual bool CkeckIfOutputIsVaild() + { + return m_output->IsVaild(); + }; + + virtual bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) + { + m_output->SetResponseCode(responseCode); + // Expected response codes. + int expectedRespCode[1] = { 200, }; + bool isExpected = false; + for (int i = 0; i < 1; i++) + { + if (expectedRespCode[i] == responseCode) + { + isExpected = true; + break; + } + } + return isExpected; + }; + virtual void ParseResponseHeaders(const Http:: + HeaderValueCollection & + headerValueCollection); +}; + +// OptionsObjectRequest ParseResponseHeaders. +void OptionsObjectUnparker::ParseResponseHeaders(const Http:: + HeaderValueCollection & + headerValueCollection) +{ + const HeaderValueCollection & headers = headerValueCollection; + HeaderValueCollection::const_iterator AccessControlAllowHeadersIter = + headers.find("access-control-allow-headers"); + if (AccessControlAllowHeadersIter != headers.end()) + { + m_output->SetAccessControlAllowHeaders(AccessControlAllowHeadersIter-> + second); + } + HeaderValueCollection::const_iterator AccessControlAllowMethodsIter = + headers.find("access-control-allow-methods"); + if (AccessControlAllowMethodsIter != headers.end()) + { + m_output->SetAccessControlAllowMethods(AccessControlAllowMethodsIter-> + second); + } + HeaderValueCollection::const_iterator AccessControlAllowOriginIter = + headers.find("access-control-allow-origin"); + if (AccessControlAllowOriginIter != headers.end()) + { + m_output->SetAccessControlAllowOrigin(AccessControlAllowOriginIter-> + second); + } + HeaderValueCollection::const_iterator AccessControlExposeHeadersIter = + headers.find("access-control-expose-headers"); + if (AccessControlExposeHeadersIter != headers.end()) + { + m_output->SetAccessControlExposeHeaders(AccessControlExposeHeadersIter-> + second); + } + HeaderValueCollection::const_iterator AccessControlMaxAgeIter = + headers.find("access-control-max-age"); + if (AccessControlMaxAgeIter != headers.end()) + { + m_output->SetAccessControlMaxAge(AccessControlMaxAgeIter->second); + } +} + +class PutObjectBuilder:public QsDefaultRequestBuilder < PutObjectInput > +{ +public: + PutObjectBuilder(PutObjectInput * input):QsDefaultRequestBuilder < + PutObjectInput > (input) + { + }; + + virtual ~ PutObjectBuilder() + { + }; + + virtual bool CkeckIfInputIsVaild() + { + return m_input->CheckIfInputIsVaild(); + }; + virtual Http::HeaderValueCollection GetHeaderValueCollection(); + virtual std::iostream * GetRequestBody(); +}; + +// PutObjectRequest GetRequestSpecificHeaders. +Http::HeaderValueCollection PutObjectBuilder::GetHeaderValueCollection() +{ + //TO DO; + Http::HeaderValueCollection headers; + std::stringstream ss; + std::vector < std::string >::iterator it; + if (m_input->IsPropHasBeenSet(SETTING_INPUT_PUT_OBJECT_CONTENT_LENGTH_FLAG)) + { + ss << m_input->GetContentLength(); + headers.insert(Http::HeaderValuePair("Content-Length", ss.str())); + ss.str(""); + } + if (m_input->IsPropHasBeenSet(SETTING_INPUT_PUT_OBJECT_CONTENT_MD5_FLAG)) + { + ss << m_input->GetContentMD5(); + headers.insert(Http::HeaderValuePair("Content-MD5", ss.str())); + ss.str(""); + } + if (m_input->IsPropHasBeenSet(SETTING_INPUT_PUT_OBJECT_CONTENT_TYPE_FLAG)) + { + ss << m_input->GetContentType(); + headers.insert(Http::HeaderValuePair("Content-Type", ss.str())); + ss.str(""); + } + if (m_input->IsPropHasBeenSet(SETTING_INPUT_PUT_OBJECT_EXPECT_FLAG)) + { + ss << m_input->GetExpect(); + headers.insert(Http::HeaderValuePair("Expect", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_FLAG)) + { + ss << m_input->GetXQSCopySource(); + headers.insert(Http::HeaderValuePair("X-QS-Copy-Source", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG)) + { + ss << m_input->GetXQSCopySourceEncryptionCustomerAlgorithm(); + headers. + insert(Http:: + HeaderValuePair + ("X-QS-Copy-Source-Encryption-Customer-Algorithm", + ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_ENCRYPTION_CUSTOMER_KEY_FLAG)) + { + ss << m_input->GetXQSCopySourceEncryptionCustomerKey(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Copy-Source-Encryption-Customer-Key", + ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG)) + { + ss << m_input->GetXQSCopySourceEncryptionCustomerKeyMD5(); + headers. + insert(Http:: + HeaderValuePair + ("X-QS-Copy-Source-Encryption-Customer-Key-MD5", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_IF_MATCH_FLAG)) + { + ss << m_input->GetXQSCopySourceIfMatch(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Copy-Source-If-Match", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_IF_MODIFIED_SINCE_FLAG)) + { + ss << m_input->GetXQSCopySourceIfModifiedSince(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Copy-Source-If-Modified-Since", + ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_IF_NONE_MATCH_FLAG)) + { + ss << m_input->GetXQSCopySourceIfNoneMatch(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Copy-Source-If-None-Match", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_PUT_OBJECT_X_QS_COPY_SOURCE_IF_UNMODIFIED_SINCE_FLAG)) + { + ss << m_input->GetXQSCopySourceIfUnmodifiedSince(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Copy-Source-If-Unmodified-Since", + ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_PUT_OBJECT_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG)) + { + ss << m_input->GetXQSEncryptionCustomerAlgorithm(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Encryption-Customer-Algorithm", + ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_PUT_OBJECT_X_QS_ENCRYPTION_CUSTOMER_KEY_FLAG)) + { + ss << m_input->GetXQSEncryptionCustomerKey(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Encryption-Customer-Key", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_PUT_OBJECT_X_QS_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG)) + { + ss << m_input->GetXQSEncryptionCustomerKeyMD5(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Encryption-Customer-Key-MD5", + ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_PUT_OBJECT_X_QS_FETCH_IF_UNMODIFIED_SINCE_FLAG)) + { + ss << m_input->GetXQSFetchIfUnmodifiedSince(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Fetch-If-Unmodified-Since", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_PUT_OBJECT_X_QS_FETCH_SOURCE_FLAG)) + { + ss << m_input->GetXQSFetchSource(); + headers.insert(Http::HeaderValuePair("X-QS-Fetch-Source", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_PUT_OBJECT_X_QS_MOVE_SOURCE_FLAG)) + { + ss << m_input->GetXQSMoveSource(); + headers.insert(Http::HeaderValuePair("X-QS-Move-Source", ss.str())); + ss.str(""); + } + return headers; +} + +// PutObjectRequest GetRequestBody. +std::iostream * PutObjectBuilder::GetRequestBody() +{ + return m_input->GetBody(); +} + +class PutObjectUnparker:public QsDefaultResponseUnparker < PutObjectOutput > +{ +public: + PutObjectUnparker(PutObjectOutput * output):QsDefaultResponseUnparker < + PutObjectOutput > (output) + { + }; + + virtual ~ PutObjectUnparker() + { + }; + + virtual bool CkeckIfOutputIsVaild() + { + return m_output->IsVaild(); + }; + + virtual bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) + { + m_output->SetResponseCode(responseCode); + // Expected response codes. + int expectedRespCode[1] = { 201, }; + bool isExpected = false; + for (int i = 0; i < 1; i++) + { + if (expectedRespCode[i] == responseCode) + { + isExpected = true; + break; + } + } + return isExpected; + }; + virtual void ParseResponseHeaders(const Http:: + HeaderValueCollection & + headerValueCollection); +}; + +// PutObjectRequest ParseResponseHeaders. +void PutObjectUnparker::ParseResponseHeaders(const Http:: + HeaderValueCollection & + headerValueCollection) +{ + const HeaderValueCollection & headers = headerValueCollection; + HeaderValueCollection::const_iterator ETagIter = headers.find("etag"); + if (ETagIter != headers.end()) + { + m_output->SetETag(ETagIter->second); + } + HeaderValueCollection::const_iterator XQSEncryptionCustomerAlgorithmIter = + headers.find("x-qs-encryption-customer-algorithm"); + if (XQSEncryptionCustomerAlgorithmIter != headers.end()) + { + m_output-> + SetXQSEncryptionCustomerAlgorithm + (XQSEncryptionCustomerAlgorithmIter->second); + } +} + +class UploadMultipartBuilder:public QsDefaultRequestBuilder < + UploadMultipartInput > +{ +public: + UploadMultipartBuilder(UploadMultipartInput * + input):QsDefaultRequestBuilder < + UploadMultipartInput > (input) + { + }; + + virtual ~ UploadMultipartBuilder() + { + }; + + virtual bool CkeckIfInputIsVaild() + { + return m_input->CheckIfInputIsVaild(); + }; + virtual Http::HeaderValueCollection GetHeaderValueCollection(); + virtual Http::QueryParamCollection GetQueryParamCollection(); + virtual std::iostream * GetRequestBody(); +}; + +// UploadMultipartRequest GetRequestSpecificHeaders. +Http::HeaderValueCollection UploadMultipartBuilder::GetHeaderValueCollection() +{ + //TO DO; + Http::HeaderValueCollection headers; + std::stringstream ss; + std::vector < std::string >::iterator it; + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_UPLOAD_MULTIPART_CONTENT_LENGTH_FLAG)) + { + ss << m_input->GetContentLength(); + headers.insert(Http::HeaderValuePair("Content-Length", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_UPLOAD_MULTIPART_CONTENT_MD5_FLAG)) + { + ss << m_input->GetContentMD5(); + headers.insert(Http::HeaderValuePair("Content-MD5", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_RANGE_FLAG)) + { + ss << m_input->GetXQSCopyRange(); + headers.insert(Http::HeaderValuePair("X-QS-Copy-Range", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_FLAG)) + { + ss << m_input->GetXQSCopySource(); + headers.insert(Http::HeaderValuePair("X-QS-Copy-Source", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG)) + { + ss << m_input->GetXQSCopySourceEncryptionCustomerAlgorithm(); + headers. + insert(Http:: + HeaderValuePair + ("X-QS-Copy-Source-Encryption-Customer-Algorithm", + ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_ENCRYPTION_CUSTOMER_KEY_FLAG)) + { + ss << m_input->GetXQSCopySourceEncryptionCustomerKey(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Copy-Source-Encryption-Customer-Key", + ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG)) + { + ss << m_input->GetXQSCopySourceEncryptionCustomerKeyMD5(); + headers. + insert(Http:: + HeaderValuePair + ("X-QS-Copy-Source-Encryption-Customer-Key-MD5", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_IF_MATCH_FLAG)) + { + ss << m_input->GetXQSCopySourceIfMatch(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Copy-Source-If-Match", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_IF_MODIFIED_SINCE_FLAG)) + { + ss << m_input->GetXQSCopySourceIfModifiedSince(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Copy-Source-If-Modified-Since", + ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_IF_NONE_MATCH_FLAG)) + { + ss << m_input->GetXQSCopySourceIfNoneMatch(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Copy-Source-If-None-Match", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_UPLOAD_MULTIPART_X_QS_COPY_SOURCE_IF_UNMODIFIED_SINCE_FLAG)) + { + ss << m_input->GetXQSCopySourceIfUnmodifiedSince(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Copy-Source-If-Unmodified-Since", + ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_UPLOAD_MULTIPART_X_QS_ENCRYPTION_CUSTOMER_ALGORITHM_FLAG)) + { + ss << m_input->GetXQSEncryptionCustomerAlgorithm(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Encryption-Customer-Algorithm", + ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_UPLOAD_MULTIPART_X_QS_ENCRYPTION_CUSTOMER_KEY_FLAG)) + { + ss << m_input->GetXQSEncryptionCustomerKey(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Encryption-Customer-Key", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet + (SETTING_INPUT_UPLOAD_MULTIPART_X_QS_ENCRYPTION_CUSTOMER_KEY_MD5_FLAG)) + { + ss << m_input->GetXQSEncryptionCustomerKeyMD5(); + headers. + insert(Http:: + HeaderValuePair("X-QS-Encryption-Customer-Key-MD5", + ss.str())); + ss.str(""); + } + return headers; +} + +// UploadMultipartRequest AddQueryStringParameters. +Http::QueryParamCollection UploadMultipartBuilder::GetQueryParamCollection() +{ + Http::QueryParamCollection queryParameters; + std::stringstream ss; + std::vector < std::string >::iterator it; + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_UPLOAD_MULTIPART_PART_NUMBER_FLAG)) + { + ss << m_input->GetPartNumber(); + queryParameters.insert(Http::HeaderValuePair("part_number", ss.str())); + ss.str(""); + } + if (m_input-> + IsPropHasBeenSet(SETTING_INPUT_UPLOAD_MULTIPART_UPLOAD_ID_FLAG)) + { + ss << m_input->GetUploadID(); + queryParameters.insert(Http::HeaderValuePair("upload_id", ss.str())); + ss.str(""); + } + return queryParameters; +} + +// UploadMultipartRequest GetRequestBody. +std::iostream * UploadMultipartBuilder::GetRequestBody() +{ + return m_input->GetBody(); +} + +class UploadMultipartUnparker:public QsDefaultResponseUnparker < + UploadMultipartOutput > +{ +public: + UploadMultipartUnparker(UploadMultipartOutput * + output):QsDefaultResponseUnparker < + UploadMultipartOutput > (output) + { + }; + + virtual ~ UploadMultipartUnparker() + { + }; + + virtual bool CkeckIfOutputIsVaild() + { + return m_output->IsVaild(); + }; + + virtual bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) + { + m_output->SetResponseCode(responseCode); + // Expected response codes. + int expectedRespCode[1] = { 201, }; + bool isExpected = false; + for (int i = 0; i < 1; i++) + { + if (expectedRespCode[i] == responseCode) + { + isExpected = true; + break; + } + } + return isExpected; + }; + virtual void ParseResponseHeaders(const Http:: + HeaderValueCollection & + headerValueCollection); +}; + +// UploadMultipartRequest ParseResponseHeaders. +void UploadMultipartUnparker::ParseResponseHeaders(const Http:: + HeaderValueCollection & + headerValueCollection) +{ + const HeaderValueCollection & headers = headerValueCollection; + HeaderValueCollection::const_iterator ETagIter = headers.find("etag"); + if (ETagIter != headers.end()) + { + m_output->SetETag(ETagIter->second); + } + HeaderValueCollection::const_iterator XQSContentCopyRangeIter = + headers.find("x-qs-content-copy-range"); + if (XQSContentCopyRangeIter != headers.end()) + { + m_output->SetXQSContentCopyRange(XQSContentCopyRangeIter->second); + } + HeaderValueCollection::const_iterator XQSEncryptionCustomerAlgorithmIter = + headers.find("x-qs-encryption-customer-algorithm"); + if (XQSEncryptionCustomerAlgorithmIter != headers.end()) + { + m_output-> + SetXQSEncryptionCustomerAlgorithm + (XQSEncryptionCustomerAlgorithmIter->second); + } +} + +// +-------------------------------------------------------------------- +// | SDK API Operation Source +// +-------------------------------------------------------------------- + +QsError Bucket::DeleteBucket(DeleteBucketInput & input, + DeleteBucketOutput & output) +{ + Properties properties(m_properties); + Operation operation(&m_qsConfig, properties, + "DELETE Bucket", HTTP_DELETE, "/"); + DeleteBucketBuilder bulider(&input); + DeleteBucketUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::DeleteBucketCORS(DeleteBucketCORSInput & input, + DeleteBucketCORSOutput & output) +{ + Properties properties(m_properties); + Operation operation(&m_qsConfig, properties, + "DELETE Bucket CORS", + HTTP_DELETE, "/?cors"); + DeleteBucketCORSBuilder bulider(&input); + DeleteBucketCORSUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket:: +DeleteBucketExternalMirror(DeleteBucketExternalMirrorInput & input, + DeleteBucketExternalMirrorOutput & output) +{ + Properties properties(m_properties); + Operation operation(&m_qsConfig, properties, + "DELETE Bucket External Mirror", + HTTP_DELETE, "/?mirror"); + DeleteBucketExternalMirrorBuilder bulider(&input); + DeleteBucketExternalMirrorUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::DeleteBucketPolicy(DeleteBucketPolicyInput & input, + DeleteBucketPolicyOutput & output) +{ + Properties properties(m_properties); + Operation operation(&m_qsConfig, properties, + "DELETE Bucket Policy", + HTTP_DELETE, "/?policy"); + DeleteBucketPolicyBuilder bulider(&input); + DeleteBucketPolicyUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::DeleteMultipleObjects(DeleteMultipleObjectsInput & input, + DeleteMultipleObjectsOutput & output) +{ + Properties properties(m_properties); + Operation operation(&m_qsConfig, properties, + "Delete Multiple Objects", + HTTP_POST, "/?delete"); + DeleteMultipleObjectsBuilder bulider(&input); + DeleteMultipleObjectsUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::GetBucketACL(GetBucketACLInput & input, + GetBucketACLOutput & output) +{ + Properties properties(m_properties); + Operation operation(&m_qsConfig, properties, + "GET Bucket ACL", HTTP_GET, "/?acl"); + GetBucketACLBuilder bulider(&input); + GetBucketACLUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::GetBucketCORS(GetBucketCORSInput & input, + GetBucketCORSOutput & output) +{ + Properties properties(m_properties); + Operation operation(&m_qsConfig, properties, + "GET Bucket CORS", HTTP_GET, "/?cors"); + GetBucketCORSBuilder bulider(&input); + GetBucketCORSUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::GetBucketExternalMirror(GetBucketExternalMirrorInput & input, + GetBucketExternalMirrorOutput & output) +{ + Properties properties(m_properties); + Operation operation(&m_qsConfig, properties, + "GET Bucket External Mirror", + HTTP_GET, "/?mirror"); + GetBucketExternalMirrorBuilder bulider(&input); + GetBucketExternalMirrorUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::GetBucketPolicy(GetBucketPolicyInput & input, + GetBucketPolicyOutput & output) +{ + Properties properties(m_properties); + Operation operation(&m_qsConfig, properties, + "GET Bucket Policy", HTTP_GET, "/?policy"); + GetBucketPolicyBuilder bulider(&input); + GetBucketPolicyUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::GetBucketStatistics(GetBucketStatisticsInput & input, + GetBucketStatisticsOutput & output) +{ + Properties properties(m_properties); + Operation operation(&m_qsConfig, properties, + "GET Bucket Statistics", + HTTP_GET, "/?stats"); + GetBucketStatisticsBuilder bulider(&input); + GetBucketStatisticsUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::HeadBucket(HeadBucketInput & input, HeadBucketOutput & output) +{ + Properties properties(m_properties); + Operation operation(&m_qsConfig, properties, + "HEAD Bucket", HTTP_HEAD, "/"); + HeadBucketBuilder bulider(&input); + HeadBucketUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::ListMultipartUploads(ListMultipartUploadsInput & input, + ListMultipartUploadsOutput & output) +{ + Properties properties(m_properties); + Operation operation(&m_qsConfig, properties, + "List Multipart Uploads", + HTTP_GET, "/?uploads"); + ListMultipartUploadsBuilder bulider(&input); + ListMultipartUploadsUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::ListObjects(ListObjectsInput & input, + ListObjectsOutput & output) +{ + Properties properties(m_properties); + Operation operation(&m_qsConfig, properties, + "GET Bucket (List Objects)", + HTTP_GET, "/"); + ListObjectsBuilder bulider(&input); + ListObjectsUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::PutBucket(PutBucketInput & input, PutBucketOutput & output) +{ + Properties properties(m_properties); + Operation operation(&m_qsConfig, properties, + "PUT Bucket", HTTP_PUT, "/"); + PutBucketBuilder bulider(&input); + PutBucketUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::PutBucketACL(PutBucketACLInput & input, + PutBucketACLOutput & output) +{ + Properties properties(m_properties); + Operation operation(&m_qsConfig, properties, + "PUT Bucket ACL", HTTP_PUT, "/?acl"); + PutBucketACLBuilder bulider(&input); + PutBucketACLUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::PutBucketCORS(PutBucketCORSInput & input, + PutBucketCORSOutput & output) +{ + Properties properties(m_properties); + Operation operation(&m_qsConfig, properties, + "PUT Bucket CORS", HTTP_PUT, "/?cors"); + PutBucketCORSBuilder bulider(&input); + PutBucketCORSUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::PutBucketExternalMirror(PutBucketExternalMirrorInput & input, + PutBucketExternalMirrorOutput & output) +{ + Properties properties(m_properties); + Operation operation(&m_qsConfig, properties, + "PUT Bucket External Mirror", + HTTP_PUT, "/?mirror"); + PutBucketExternalMirrorBuilder bulider(&input); + PutBucketExternalMirrorUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::PutBucketPolicy(PutBucketPolicyInput & input, + PutBucketPolicyOutput & output) +{ + Properties properties(m_properties); + Operation operation(&m_qsConfig, properties, + "PUT Bucket Policy", HTTP_PUT, "/?policy"); + PutBucketPolicyBuilder bulider(&input); + PutBucketPolicyUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +// +-------------------------------------------------------------------- +// | SDK API Operation Source +// +-------------------------------------------------------------------- + +QsError Bucket::AbortMultipartUpload(std::string objectKey, + AbortMultipartUploadInput & input, + AbortMultipartUploadOutput & output) +{ + Properties properties(m_properties); + properties.ObjectKey = objectKey; + Operation operation(&m_qsConfig, properties, + "Abort Multipart Upload", + HTTP_DELETE, "//"); + AbortMultipartUploadBuilder bulider(&input); + AbortMultipartUploadUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::CompleteMultipartUpload(std::string objectKey, + CompleteMultipartUploadInput & input, + CompleteMultipartUploadOutput & output) +{ + Properties properties(m_properties); + properties.ObjectKey = objectKey; + Operation operation(&m_qsConfig, properties, + "Complete multipart upload", + HTTP_POST, "//"); + CompleteMultipartUploadBuilder bulider(&input); + CompleteMultipartUploadUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::DeleteObject(std::string objectKey, DeleteObjectInput & input, + DeleteObjectOutput & output) +{ + Properties properties(m_properties); + properties.ObjectKey = objectKey; + Operation operation(&m_qsConfig, properties, + "DELETE Object", + HTTP_DELETE, "//"); + DeleteObjectBuilder bulider(&input); + DeleteObjectUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::GetObject(std::string objectKey, GetObjectInput & input, + GetObjectOutput & output) +{ + Properties properties(m_properties); + properties.ObjectKey = objectKey; + Operation operation(&m_qsConfig, properties, + "GET Object", HTTP_GET, "//"); + GetObjectBuilder bulider(&input); + GetObjectUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::HeadObject(std::string objectKey, HeadObjectInput & input, + HeadObjectOutput & output) +{ + Properties properties(m_properties); + properties.ObjectKey = objectKey; + Operation operation(&m_qsConfig, properties, + "HEAD Object", + HTTP_HEAD, "//"); + HeadObjectBuilder bulider(&input); + HeadObjectUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::ImageProcess(std::string objectKey, ImageProcessInput & input, + ImageProcessOutput & output) +{ + Properties properties(m_properties); + properties.ObjectKey = objectKey; + Operation operation(&m_qsConfig, properties, + "Image Process", + HTTP_GET, "//?image"); + ImageProcessBuilder bulider(&input); + ImageProcessUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::InitiateMultipartUpload(std::string objectKey, + InitiateMultipartUploadInput & input, + InitiateMultipartUploadOutput & output) +{ + Properties properties(m_properties); + properties.ObjectKey = objectKey; + Operation operation(&m_qsConfig, properties, + "Initiate Multipart Upload", + HTTP_POST, "//?uploads"); + InitiateMultipartUploadBuilder bulider(&input); + InitiateMultipartUploadUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::ListMultipart(std::string objectKey, ListMultipartInput & input, + ListMultipartOutput & output) +{ + Properties properties(m_properties); + properties.ObjectKey = objectKey; + Operation operation(&m_qsConfig, properties, + "List Multipart", + HTTP_GET, "//"); + ListMultipartBuilder bulider(&input); + ListMultipartUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::OptionsObject(std::string objectKey, OptionsObjectInput & input, + OptionsObjectOutput & output) +{ + Properties properties(m_properties); + properties.ObjectKey = objectKey; + Operation operation(&m_qsConfig, properties, + "OPTIONS Object", + HTTP_OPTIONS, "//"); + OptionsObjectBuilder bulider(&input); + OptionsObjectUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::PutObject(std::string objectKey, PutObjectInput & input, + PutObjectOutput & output) +{ + Properties properties(m_properties); + properties.ObjectKey = objectKey; + Operation operation(&m_qsConfig, properties, + "PUT Object", HTTP_PUT, "//"); + PutObjectBuilder bulider(&input); + PutObjectUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} + +QsError Bucket::UploadMultipart(std::string objectKey, + UploadMultipartInput & input, + UploadMultipartOutput & output) +{ + Properties properties(m_properties); + properties.ObjectKey = objectKey; + Operation operation(&m_qsConfig, properties, + "Upload Multipart", + HTTP_PUT, "//"); + UploadMultipartBuilder bulider(&input); + UploadMultipartUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} diff --git a/src/service/QingStor.cpp b/src/service/QingStor.cpp new file mode 100644 index 0000000..be9d994 --- /dev/null +++ b/src/service/QingStor.cpp @@ -0,0 +1,168 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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 "QingStor.h" +#include "Bucket.h" +#include "QsConfig.h" +#include "request/QsRequest.h" +#include "http/HttpResponse.h" +#include "external/plog/Log.h" +#include "external/json/json.h" + +using namespace QingStor; + +void QingStor::InitializeSDK(const SDKOptions & options) +{ + //Init log systom + LOG_DEBUG << "Initializing SDK..."; + std::string logName = options.logPath; + logName += "qingstor_sdk_log.txt"; + plog::init((plog::Severity) options.logLevel, logName.c_str(), 1000000, 5); + if (options.initAndCleanupCurl) + { + //InitHttp + curl_global_init(CURL_GLOBAL_ALL); + LOG_DEBUG << "curl_global_init done"; + } + HttpClient::CreateGlobaleCurlPool(); +} + +void QingStor::ShutdownSDK(const SDKOptions & options) +{ + LOG_DEBUG << "Shutdowning SDK..."; + if (options.initAndCleanupCurl) + { + //InitHttp + curl_global_cleanup(); + LOG_DEBUG << "curl_global_cleanup done"; + } + HttpClient::DestroyGlobaleCurlPool(); +} + +QingStorService::QingStorService(const QsConfig & qsConfig):m_qsConfig(qsConfig) +{ +} + +// +-------------------------------------------------------------------- +// | RequestBuilderSource and ResponseUnparkerSource +// +-------------------------------------------------------------------- +class ListBucketsBuilder:public QsDefaultRequestBuilder < ListBucketsInput > +{ +public: + ListBucketsBuilder(ListBucketsInput * input):QsDefaultRequestBuilder < + ListBucketsInput > (input) + { + }; + + virtual ~ ListBucketsBuilder() + { + }; + + virtual bool CkeckIfInputIsVaild() + { + return m_input->CheckIfInputIsVaild(); + }; + virtual Http::HeaderValueCollection GetHeaderValueCollection(); +}; + +// ListBucketsRequest GetRequestSpecificHeaders. +Http::HeaderValueCollection ListBucketsBuilder::GetHeaderValueCollection() +{ + //TO DO; + Http::HeaderValueCollection headers; + std::stringstream ss; + std::vector < std::string >::iterator it; + if (m_input->IsPropHasBeenSet(SETTING_INPUT_LIST_BUCKETS_LOCATION_FLAG)) + { + ss << m_input->GetLocation(); + headers.insert(Http::HeaderValuePair("Location", ss.str())); + ss.str(""); + } + return headers; +} + +class ListBucketsUnparker:public QsDefaultResponseUnparker < ListBucketsOutput > +{ +public: + ListBucketsUnparker(ListBucketsOutput * output):QsDefaultResponseUnparker < + ListBucketsOutput > (output) + { + }; + + virtual ~ ListBucketsUnparker() + { + }; + + virtual bool CkeckIfOutputIsVaild() + { + return m_output->IsVaild(); + }; + + virtual bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) + { + m_output->SetResponseCode(responseCode); + // Expected response codes. + int expectedRespCode[1] = { 200, }; + bool isExpected = false; + for (int i = 0; i < 1; i++) + { + if (expectedRespCode[i] == responseCode) + { + isExpected = true; + break; + } + } + return isExpected; + }; + virtual void ParseResponseBody(std::iostream * responseBody); +}; + +void ListBucketsUnparker::ParseResponseBody(std::iostream * responseBody) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(*responseBody, jsonContent); + if (jsonContent.isMember("buckets")) + { + std::vector < BucketType > vecBuckets; + for (unsigned i = 0; i < jsonContent["buckets"].size(); ++i) + { + vecBuckets.push_back(jsonContent["buckets"][i].toStyledString()); + } + m_output->SetBuckets(vecBuckets); + } + if (jsonContent.isMember("count")) + { + m_output->SetCount(jsonContent["count"].asInt()); + } + m_bNeedReleaseBody = true; +} + +// +-------------------------------------------------------------------- +// | SDK API Operation Source +// +-------------------------------------------------------------------- + +QsError QingStorService::ListBuckets(ListBucketsInput & input, + ListBucketsOutput & output) +{ + Properties properties(m_properties); + Operation operation(&m_qsConfig, properties, "Get Service", HTTP_GET, "/"); + ListBucketsBuilder bulider(&input); + ListBucketsUnparker unparker(&output); + QsRequest request(operation, &bulider, &unparker); + return request.GetResponse(); +} diff --git a/src/service/Types.cpp b/src/service/Types.cpp new file mode 100644 index 0000000..2cdb353 --- /dev/null +++ b/src/service/Types.cpp @@ -0,0 +1,1667 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +// Headers of CustomizedType. +#include "Types.h" +#include "external/json/json.h" +#include +#include +#include +#include +#include + +#ifdef BUILD_C_STYLE_INTERFACE +ACLType::ACLType(qs_acl_t acl) +{ + if (acl.grantee) + SetGrantee(*acl.grantee); + if (acl.permission) + SetPermission(acl.permission); +} + +qs_acl_t *ACLType::toCStyleObj() +{ + qs_acl_t *acl = (qs_acl_t *) malloc(sizeof(qs_acl_t)); + acl->grantee = GetGrantee().toCStyleObj(); + int permissionLength = 0; + permissionLength = GetPermission().length(); + if (permissionLength > 0) + { + acl->permission = (char *) malloc(permissionLength + 1); + memset(acl->permission, 0, permissionLength + 1); + strncpy(acl->permission, GetPermission().c_str(), permissionLength); + } + else + { + acl->permission = NULL; + } + return acl; +} + +#endif // BUILD_C_STYLE_INTERFACE + +ACLType::ACLType(std::string serializedString) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(serializedString, jsonContent); + if (jsonContent.isMember("grantee")) + { + SetGrantee(jsonContent["grantee"].toStyledString()); + } + if (jsonContent.isMember("permission")) + { + SetPermission(jsonContent["permission"].asString()); + } +} + +std::string ACLType::Serialize() +{ + Json::Value jsonContent; + Json::FastWriter jsonWriter; + if (m_settingFlag & SETTING_ACL_GRANTEE_FLAG) + { + Json::Reader jsonReader; + Json::Value itemJsonValue; + jsonReader.parse(m_Grantee.Serialize(), itemJsonValue); + jsonContent["grantee"] = itemJsonValue; + } + if (m_settingFlag & SETTING_ACL_PERMISSION_FLAG) + { + jsonContent["permission"] = m_Permission; + } + return jsonWriter.write(jsonContent); +} + +#ifdef BUILD_C_STYLE_INTERFACE +BucketType::BucketType(qs_bucket_t bucket) +{ + if (bucket.created) + SetCreated(bucket.created); + if (bucket.location) + SetLocation(bucket.location); + if (bucket.name) + SetName(bucket.name); + if (bucket.url) + SetURL(bucket.url); +} + +qs_bucket_t *BucketType::toCStyleObj() +{ + qs_bucket_t *bucket = (qs_bucket_t *) malloc(sizeof(qs_bucket_t)); + int createdLength = 0; + createdLength = GetCreated().length(); + if (createdLength > 0) + { + bucket->created = (char *) malloc(createdLength + 1); + memset(bucket->created, 0, createdLength + 1); + strncpy(bucket->created, GetCreated().c_str(), createdLength); + } + else + { + bucket->created = NULL; + } + int locationLength = 0; + locationLength = GetLocation().length(); + if (locationLength > 0) + { + bucket->location = (char *) malloc(locationLength + 1); + memset(bucket->location, 0, locationLength + 1); + strncpy(bucket->location, GetLocation().c_str(), locationLength); + } + else + { + bucket->location = NULL; + } + int nameLength = 0; + nameLength = GetName().length(); + if (nameLength > 0) + { + bucket->name = (char *) malloc(nameLength + 1); + memset(bucket->name, 0, nameLength + 1); + strncpy(bucket->name, GetName().c_str(), nameLength); + } + else + { + bucket->name = NULL; + } + int urlLength = 0; + urlLength = GetURL().length(); + if (urlLength > 0) + { + bucket->url = (char *) malloc(urlLength + 1); + memset(bucket->url, 0, urlLength + 1); + strncpy(bucket->url, GetURL().c_str(), urlLength); + } + else + { + bucket->url = NULL; + } + return bucket; +} + +#endif // BUILD_C_STYLE_INTERFACE + +BucketType::BucketType(std::string serializedString) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(serializedString, jsonContent); + if (jsonContent.isMember("created")) + { + SetCreated(jsonContent["created"].asString()); + } + if (jsonContent.isMember("location")) + { + SetLocation(jsonContent["location"].asString()); + } + if (jsonContent.isMember("name")) + { + SetName(jsonContent["name"].asString()); + } + if (jsonContent.isMember("url")) + { + SetURL(jsonContent["url"].asString()); + } +} + +std::string BucketType::Serialize() +{ + Json::Value jsonContent; + Json::FastWriter jsonWriter; + if (m_settingFlag & SETTING_BUCKET_CREATED_FLAG) + { + jsonContent["created"] = m_Created; + } + if (m_settingFlag & SETTING_BUCKET_LOCATION_FLAG) + { + jsonContent["location"] = m_Location; + } + if (m_settingFlag & SETTING_BUCKET_NAME_FLAG) + { + jsonContent["name"] = m_Name; + } + if (m_settingFlag & SETTING_BUCKET_URL_FLAG) + { + jsonContent["url"] = m_URL; + } + return jsonWriter.write(jsonContent); +} + +#ifdef BUILD_C_STYLE_INTERFACE +ConditionType::ConditionType(qs_condition_t condition) +{ + if (condition.ip_address) + SetIPAddress(*condition.ip_address); + if (condition.is_null) + SetIsNull(*condition.is_null); + if (condition.not_ip_address) + SetNotIPAddress(*condition.not_ip_address); + if (condition.string_like) + SetStringLike(*condition.string_like); + if (condition.string_not_like) + SetStringNotLike(*condition.string_not_like); +} + +qs_condition_t *ConditionType::toCStyleObj() +{ + qs_condition_t *condition = + (qs_condition_t *) malloc(sizeof(qs_condition_t)); + condition->ip_address = GetIPAddress().toCStyleObj(); + condition->is_null = GetIsNull().toCStyleObj(); + condition->not_ip_address = GetNotIPAddress().toCStyleObj(); + condition->string_like = GetStringLike().toCStyleObj(); + condition->string_not_like = GetStringNotLike().toCStyleObj(); + return condition; +} + +#endif // BUILD_C_STYLE_INTERFACE + +ConditionType::ConditionType(std::string serializedString) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(serializedString, jsonContent); + if (jsonContent.isMember("ip_address")) + { + SetIPAddress(jsonContent["ip_address"].toStyledString()); + } + if (jsonContent.isMember("is_null")) + { + SetIsNull(jsonContent["is_null"].toStyledString()); + } + if (jsonContent.isMember("not_ip_address")) + { + SetNotIPAddress(jsonContent["not_ip_address"].toStyledString()); + } + if (jsonContent.isMember("string_like")) + { + SetStringLike(jsonContent["string_like"].toStyledString()); + } + if (jsonContent.isMember("string_not_like")) + { + SetStringNotLike(jsonContent["string_not_like"].toStyledString()); + } +} + +std::string ConditionType::Serialize() +{ + Json::Value jsonContent; + Json::FastWriter jsonWriter; + if (m_settingFlag & SETTING_CONDITION_IP_ADDRESS_FLAG) + { + Json::Reader jsonReader; + Json::Value itemJsonValue; + jsonReader.parse(m_IPAddress.Serialize(), itemJsonValue); + jsonContent["ip_address"] = itemJsonValue; + } + if (m_settingFlag & SETTING_CONDITION_IS_NULL_FLAG) + { + Json::Reader jsonReader; + Json::Value itemJsonValue; + jsonReader.parse(m_IsNull.Serialize(), itemJsonValue); + jsonContent["is_null"] = itemJsonValue; + } + if (m_settingFlag & SETTING_CONDITION_NOT_IP_ADDRESS_FLAG) + { + Json::Reader jsonReader; + Json::Value itemJsonValue; + jsonReader.parse(m_NotIPAddress.Serialize(), itemJsonValue); + jsonContent["not_ip_address"] = itemJsonValue; + } + if (m_settingFlag & SETTING_CONDITION_STRING_LIKE_FLAG) + { + Json::Reader jsonReader; + Json::Value itemJsonValue; + jsonReader.parse(m_StringLike.Serialize(), itemJsonValue); + jsonContent["string_like"] = itemJsonValue; + } + if (m_settingFlag & SETTING_CONDITION_STRING_NOT_LIKE_FLAG) + { + Json::Reader jsonReader; + Json::Value itemJsonValue; + jsonReader.parse(m_StringNotLike.Serialize(), itemJsonValue); + jsonContent["string_not_like"] = itemJsonValue; + } + return jsonWriter.write(jsonContent); +} + +#ifdef BUILD_C_STYLE_INTERFACE +CORSRuleType::CORSRuleType(qs_cors_rule_t cors_rule) +{ + if (cors_rule.allowed_headers) + SetAllowedHeaders(cors_rule.allowed_headers); + if (cors_rule.allowed_methods) + SetAllowedMethods(cors_rule.allowed_methods); + if (cors_rule.allowed_origin) + SetAllowedOrigin(cors_rule.allowed_origin); + if (cors_rule.expose_headers) + SetExposeHeaders(cors_rule.expose_headers); + if (cors_rule.max_age_seconds) + SetMaxAgeSeconds(*cors_rule.max_age_seconds); +} + +qs_cors_rule_t *CORSRuleType::toCStyleObj() +{ + qs_cors_rule_t *cors_rule = + (qs_cors_rule_t *) malloc(sizeof(qs_cors_rule_t)); + qs_list_t *list_allowed_headers = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(list_allowed_headers); + std::vector < std::string > allowedHeaders = GetAllowedHeaders(); + for (std::vector < std::string >::iterator it = allowedHeaders.begin(); + it != allowedHeaders.end(); it++) + { + qs_cors_rule_allowed_headers_item_t *item = + (qs_cors_rule_allowed_headers_item_t *) + malloc(sizeof(qs_cors_rule_allowed_headers_item_t)); + int allowedHeadersLength = it->length(); + if (allowedHeadersLength > 0) + { + item->content = (char *) malloc(allowedHeadersLength + 1); + memset(item->content, 0, allowedHeadersLength + 1); + strncpy(item->content, it->c_str(), allowedHeadersLength); + } + else + { + item->content = NULL; + } + qs_list_append(&item->node, list_allowed_headers); + } + cors_rule->allowed_headers = list_allowed_headers; + qs_list_t *list_allowed_methods = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(list_allowed_methods); + std::vector < std::string > allowedMethods = GetAllowedMethods(); + for (std::vector < std::string >::iterator it = allowedMethods.begin(); + it != allowedMethods.end(); it++) + { + qs_cors_rule_allowed_methods_item_t *item = + (qs_cors_rule_allowed_methods_item_t *) + malloc(sizeof(qs_cors_rule_allowed_methods_item_t)); + int allowedMethodsLength = it->length(); + if (allowedMethodsLength > 0) + { + item->content = (char *) malloc(allowedMethodsLength + 1); + memset(item->content, 0, allowedMethodsLength + 1); + strncpy(item->content, it->c_str(), allowedMethodsLength); + } + else + { + item->content = NULL; + } + qs_list_append(&item->node, list_allowed_methods); + } + cors_rule->allowed_methods = list_allowed_methods; + int allowedOriginLength = 0; + allowedOriginLength = GetAllowedOrigin().length(); + if (allowedOriginLength > 0) + { + cors_rule->allowed_origin = (char *) malloc(allowedOriginLength + 1); + memset(cors_rule->allowed_origin, 0, allowedOriginLength + 1); + strncpy(cors_rule->allowed_origin, GetAllowedOrigin().c_str(), + allowedOriginLength); + } + else + { + cors_rule->allowed_origin = NULL; + } + qs_list_t *list_expose_headers = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(list_expose_headers); + std::vector < std::string > exposeHeaders = GetExposeHeaders(); + for (std::vector < std::string >::iterator it = exposeHeaders.begin(); + it != exposeHeaders.end(); it++) + { + qs_cors_rule_expose_headers_item_t *item = + (qs_cors_rule_expose_headers_item_t *) + malloc(sizeof(qs_cors_rule_expose_headers_item_t)); + int exposeHeadersLength = it->length(); + if (exposeHeadersLength > 0) + { + item->content = (char *) malloc(exposeHeadersLength + 1); + memset(item->content, 0, exposeHeadersLength + 1); + strncpy(item->content, it->c_str(), exposeHeadersLength); + } + else + { + item->content = NULL; + } + qs_list_append(&item->node, list_expose_headers); + } + cors_rule->expose_headers = list_expose_headers; + cors_rule->max_age_seconds = (int *) malloc(sizeof(int)); + *cors_rule->max_age_seconds = GetMaxAgeSeconds(); + return cors_rule; +} + +#endif // BUILD_C_STYLE_INTERFACE + +CORSRuleType::CORSRuleType(std::string serializedString) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(serializedString, jsonContent); + if (jsonContent.isMember("allowed_headers")) + { + std::vector < std::string > vecAllowedHeaders; + for (unsigned i = 0; i < jsonContent["allowed_headers"].size(); ++i) + { + vecAllowedHeaders.push_back(jsonContent["allowed_headers"][i]. + asString()); + } + SetAllowedHeaders(vecAllowedHeaders); + } + if (jsonContent.isMember("allowed_methods")) + { + std::vector < std::string > vecAllowedMethods; + for (unsigned i = 0; i < jsonContent["allowed_methods"].size(); ++i) + { + vecAllowedMethods.push_back(jsonContent["allowed_methods"][i]. + asString()); + } + SetAllowedMethods(vecAllowedMethods); + } + if (jsonContent.isMember("allowed_origin")) + { + SetAllowedOrigin(jsonContent["allowed_origin"].asString()); + } + if (jsonContent.isMember("expose_headers")) + { + std::vector < std::string > vecExposeHeaders; + for (unsigned i = 0; i < jsonContent["expose_headers"].size(); ++i) + { + vecExposeHeaders.push_back(jsonContent["expose_headers"][i]. + asString()); + } + SetExposeHeaders(vecExposeHeaders); + } + if (jsonContent.isMember("max_age_seconds")) + { + SetMaxAgeSeconds(jsonContent["max_age_seconds"].asInt()); + } +} + +std::string CORSRuleType::Serialize() +{ + Json::Value jsonContent; + Json::FastWriter jsonWriter; + if (m_settingFlag & SETTING_CORS_RULE_ALLOWED_HEADERS_FLAG) + { + Json::Value arrayAllowedHeaders; + std::vector < std::string > allowedHeaders = m_AllowedHeaders; + for (std::vector < std::string >::iterator it = allowedHeaders.begin(); + it != allowedHeaders.end(); it++) + { + arrayAllowedHeaders.append(*it); + } + jsonContent["allowed_headers"] = arrayAllowedHeaders; + } + if (m_settingFlag & SETTING_CORS_RULE_ALLOWED_METHODS_FLAG) + { + Json::Value arrayAllowedMethods; + std::vector < std::string > allowedMethods = m_AllowedMethods; + for (std::vector < std::string >::iterator it = allowedMethods.begin(); + it != allowedMethods.end(); it++) + { + arrayAllowedMethods.append(*it); + } + jsonContent["allowed_methods"] = arrayAllowedMethods; + } + if (m_settingFlag & SETTING_CORS_RULE_ALLOWED_ORIGIN_FLAG) + { + jsonContent["allowed_origin"] = m_AllowedOrigin; + } + if (m_settingFlag & SETTING_CORS_RULE_EXPOSE_HEADERS_FLAG) + { + Json::Value arrayExposeHeaders; + std::vector < std::string > exposeHeaders = m_ExposeHeaders; + for (std::vector < std::string >::iterator it = exposeHeaders.begin(); + it != exposeHeaders.end(); it++) + { + arrayExposeHeaders.append(*it); + } + jsonContent["expose_headers"] = arrayExposeHeaders; + } + if (m_settingFlag & SETTING_CORS_RULE_MAX_AGE_SECONDS_FLAG) + { + jsonContent["max_age_seconds"] = m_MaxAgeSeconds; + } + return jsonWriter.write(jsonContent); +} + +#ifdef BUILD_C_STYLE_INTERFACE +GranteeType::GranteeType(qs_grantee_t grantee) +{ + if (grantee.id) + SetID(grantee.id); + if (grantee.name) + SetName(grantee.name); + if (grantee.type) + SetType(grantee.type); +} + +qs_grantee_t *GranteeType::toCStyleObj() +{ + qs_grantee_t *grantee = (qs_grantee_t *) malloc(sizeof(qs_grantee_t)); + int idLength = 0; + idLength = GetID().length(); + if (idLength > 0) + { + grantee->id = (char *) malloc(idLength + 1); + memset(grantee->id, 0, idLength + 1); + strncpy(grantee->id, GetID().c_str(), idLength); + } + else + { + grantee->id = NULL; + } + int nameLength = 0; + nameLength = GetName().length(); + if (nameLength > 0) + { + grantee->name = (char *) malloc(nameLength + 1); + memset(grantee->name, 0, nameLength + 1); + strncpy(grantee->name, GetName().c_str(), nameLength); + } + else + { + grantee->name = NULL; + } + int typeLength = 0; + typeLength = GetType().length(); + if (typeLength > 0) + { + grantee->type = (char *) malloc(typeLength + 1); + memset(grantee->type, 0, typeLength + 1); + strncpy(grantee->type, GetType().c_str(), typeLength); + } + else + { + grantee->type = NULL; + } + return grantee; +} + +#endif // BUILD_C_STYLE_INTERFACE + +GranteeType::GranteeType(std::string serializedString) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(serializedString, jsonContent); + if (jsonContent.isMember("id")) + { + SetID(jsonContent["id"].asString()); + } + if (jsonContent.isMember("name")) + { + SetName(jsonContent["name"].asString()); + } + if (jsonContent.isMember("type")) + { + SetType(jsonContent["type"].asString()); + } +} + +std::string GranteeType::Serialize() +{ + Json::Value jsonContent; + Json::FastWriter jsonWriter; + if (m_settingFlag & SETTING_GRANTEE_ID_FLAG) + { + jsonContent["id"] = m_ID; + } + if (m_settingFlag & SETTING_GRANTEE_NAME_FLAG) + { + jsonContent["name"] = m_Name; + } + if (m_settingFlag & SETTING_GRANTEE_TYPE_FLAG) + { + jsonContent["type"] = m_Type; + } + return jsonWriter.write(jsonContent); +} + +#ifdef BUILD_C_STYLE_INTERFACE +IPAddressType::IPAddressType(qs_ip_address_t ip_address) +{ + if (ip_address.source_ip) + SetSourceIP(ip_address.source_ip); +} + +qs_ip_address_t *IPAddressType::toCStyleObj() +{ + qs_ip_address_t *ip_address = + (qs_ip_address_t *) malloc(sizeof(qs_ip_address_t)); + qs_list_t *list_source_ip = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(list_source_ip); + std::vector < std::string > sourceIP = GetSourceIP(); + for (std::vector < std::string >::iterator it = sourceIP.begin(); + it != sourceIP.end(); it++) + { + qs_ip_address_source_ip_item_t *item = + (qs_ip_address_source_ip_item_t *) + malloc(sizeof(qs_ip_address_source_ip_item_t)); + int sourceIPLength = it->length(); + if (sourceIPLength > 0) + { + item->content = (char *) malloc(sourceIPLength + 1); + memset(item->content, 0, sourceIPLength + 1); + strncpy(item->content, it->c_str(), sourceIPLength); + } + else + { + item->content = NULL; + } + qs_list_append(&item->node, list_source_ip); + } + ip_address->source_ip = list_source_ip; + return ip_address; +} + +#endif // BUILD_C_STYLE_INTERFACE + +IPAddressType::IPAddressType(std::string serializedString) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(serializedString, jsonContent); + if (jsonContent.isMember("source_ip")) + { + std::vector < std::string > vecSourceIP; + for (unsigned i = 0; i < jsonContent["source_ip"].size(); ++i) + { + vecSourceIP.push_back(jsonContent["source_ip"][i].asString()); + } + SetSourceIP(vecSourceIP); + } +} + +std::string IPAddressType::Serialize() +{ + Json::Value jsonContent; + Json::FastWriter jsonWriter; + if (m_settingFlag & SETTING_IP_ADDRESS_SOURCE_IP_FLAG) + { + Json::Value arraySourceIP; + std::vector < std::string > sourceIP = m_SourceIP; + for (std::vector < std::string >::iterator it = sourceIP.begin(); + it != sourceIP.end(); it++) + { + arraySourceIP.append(*it); + } + jsonContent["source_ip"] = arraySourceIP; + } + return jsonWriter.write(jsonContent); +} + +#ifdef BUILD_C_STYLE_INTERFACE +IsNullType::IsNullType(qs_is_null_t is_null) +{ + if (is_null.referer) + SetReferer(*is_null.referer); +} + +qs_is_null_t *IsNullType::toCStyleObj() +{ + qs_is_null_t *is_null = (qs_is_null_t *) malloc(sizeof(qs_is_null_t)); + is_null->referer = (int *) malloc(sizeof(int)); + *is_null->referer = (int) GetReferer(); + return is_null; +} + +#endif // BUILD_C_STYLE_INTERFACE + +IsNullType::IsNullType(std::string serializedString) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(serializedString, jsonContent); + if (jsonContent.isMember("Referer")) + { + SetReferer(jsonContent["Referer"].asBool()); + } +} + +std::string IsNullType::Serialize() +{ + Json::Value jsonContent; + Json::FastWriter jsonWriter; + if (m_settingFlag & SETTING_IS_NULL_REFERER_FLAG) + { + jsonContent["Referer"] = m_Referer; + } + return jsonWriter.write(jsonContent); +} + +#ifdef BUILD_C_STYLE_INTERFACE +KeyType::KeyType(qs_key_t key) +{ + if (key.created) + SetCreated(key.created); + if (key.encrypted) + SetEncrypted(*key.encrypted); + if (key.etag) + SetEtag(key.etag); + if (key.key) + SetKey(key.key); + if (key.mime_type) + SetMimeType(key.mime_type); + if (key.modified) + SetModified(*key.modified); + if (key.size) + SetSize(*key.size); +} + +qs_key_t *KeyType::toCStyleObj() +{ + qs_key_t *key = (qs_key_t *) malloc(sizeof(qs_key_t)); + int createdLength = 0; + createdLength = GetCreated().length(); + if (createdLength > 0) + { + key->created = (char *) malloc(createdLength + 1); + memset(key->created, 0, createdLength + 1); + strncpy(key->created, GetCreated().c_str(), createdLength); + } + else + { + key->created = NULL; + } + key->encrypted = (int *) malloc(sizeof(int)); + *key->encrypted = (int) GetEncrypted(); + int etagLength = 0; + etagLength = GetEtag().length(); + if (etagLength > 0) + { + key->etag = (char *) malloc(etagLength + 1); + memset(key->etag, 0, etagLength + 1); + strncpy(key->etag, GetEtag().c_str(), etagLength); + } + else + { + key->etag = NULL; + } + int keyLength = 0; + keyLength = GetKey().length(); + if (keyLength > 0) + { + key->key = (char *) malloc(keyLength + 1); + memset(key->key, 0, keyLength + 1); + strncpy(key->key, GetKey().c_str(), keyLength); + } + else + { + key->key = NULL; + } + int mimeTypeLength = 0; + mimeTypeLength = GetMimeType().length(); + if (mimeTypeLength > 0) + { + key->mime_type = (char *) malloc(mimeTypeLength + 1); + memset(key->mime_type, 0, mimeTypeLength + 1); + strncpy(key->mime_type, GetMimeType().c_str(), mimeTypeLength); + } + else + { + key->mime_type = NULL; + } + key->modified = (int *) malloc(sizeof(int)); + *key->modified = GetModified(); + key->size = (long *) malloc(sizeof(long)); + *key->size = GetSize(); + return key; +} + +#endif // BUILD_C_STYLE_INTERFACE + +KeyType::KeyType(std::string serializedString) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(serializedString, jsonContent); + if (jsonContent.isMember("created")) + { + SetCreated(jsonContent["created"].asString()); + } + if (jsonContent.isMember("encrypted")) + { + SetEncrypted(jsonContent["encrypted"].asBool()); + } + if (jsonContent.isMember("etag")) + { + SetEtag(jsonContent["etag"].asString()); + } + if (jsonContent.isMember("key")) + { + SetKey(jsonContent["key"].asString()); + } + if (jsonContent.isMember("mime_type")) + { + SetMimeType(jsonContent["mime_type"].asString()); + } + if (jsonContent.isMember("modified")) + { + SetModified(jsonContent["modified"].asInt()); + } + if (jsonContent.isMember("size")) + { + SetSize(jsonContent["size"].asInt64()); + } +} + +std::string KeyType::Serialize() +{ + Json::Value jsonContent; + Json::FastWriter jsonWriter; + if (m_settingFlag & SETTING_KEY_CREATED_FLAG) + { + jsonContent["created"] = m_Created; + } + if (m_settingFlag & SETTING_KEY_ENCRYPTED_FLAG) + { + jsonContent["encrypted"] = m_Encrypted; + } + if (m_settingFlag & SETTING_KEY_ETAG_FLAG) + { + jsonContent["etag"] = m_Etag; + } + if (m_settingFlag & SETTING_KEY_KEY_FLAG) + { + jsonContent["key"] = m_Key; + } + if (m_settingFlag & SETTING_KEY_MIME_TYPE_FLAG) + { + jsonContent["mime_type"] = m_MimeType; + } + if (m_settingFlag & SETTING_KEY_MODIFIED_FLAG) + { + jsonContent["modified"] = m_Modified; + } + if (m_settingFlag & SETTING_KEY_SIZE_FLAG) + { + jsonContent["size"] = (Json::Int64) m_Size; + } + return jsonWriter.write(jsonContent); +} + +#ifdef BUILD_C_STYLE_INTERFACE +KeyDeleteErrorType::KeyDeleteErrorType(qs_key_delete_error_t key_delete_error) +{ + if (key_delete_error.code) + SetCode(key_delete_error.code); + if (key_delete_error.key) + SetKey(key_delete_error.key); + if (key_delete_error.message) + SetMessage(key_delete_error.message); +} + +qs_key_delete_error_t *KeyDeleteErrorType::toCStyleObj() +{ + qs_key_delete_error_t *key_delete_error = + (qs_key_delete_error_t *) malloc(sizeof(qs_key_delete_error_t)); + int codeLength = 0; + codeLength = GetCode().length(); + if (codeLength > 0) + { + key_delete_error->code = (char *) malloc(codeLength + 1); + memset(key_delete_error->code, 0, codeLength + 1); + strncpy(key_delete_error->code, GetCode().c_str(), codeLength); + } + else + { + key_delete_error->code = NULL; + } + int keyLength = 0; + keyLength = GetKey().length(); + if (keyLength > 0) + { + key_delete_error->key = (char *) malloc(keyLength + 1); + memset(key_delete_error->key, 0, keyLength + 1); + strncpy(key_delete_error->key, GetKey().c_str(), keyLength); + } + else + { + key_delete_error->key = NULL; + } + int messageLength = 0; + messageLength = GetMessage().length(); + if (messageLength > 0) + { + key_delete_error->message = (char *) malloc(messageLength + 1); + memset(key_delete_error->message, 0, messageLength + 1); + strncpy(key_delete_error->message, GetMessage().c_str(), messageLength); + } + else + { + key_delete_error->message = NULL; + } + return key_delete_error; +} + +#endif // BUILD_C_STYLE_INTERFACE + +KeyDeleteErrorType::KeyDeleteErrorType(std::string serializedString) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(serializedString, jsonContent); + if (jsonContent.isMember("code")) + { + SetCode(jsonContent["code"].asString()); + } + if (jsonContent.isMember("key")) + { + SetKey(jsonContent["key"].asString()); + } + if (jsonContent.isMember("message")) + { + SetMessage(jsonContent["message"].asString()); + } +} + +std::string KeyDeleteErrorType::Serialize() +{ + Json::Value jsonContent; + Json::FastWriter jsonWriter; + if (m_settingFlag & SETTING_KEY_DELETE_ERROR_CODE_FLAG) + { + jsonContent["code"] = m_Code; + } + if (m_settingFlag & SETTING_KEY_DELETE_ERROR_KEY_FLAG) + { + jsonContent["key"] = m_Key; + } + if (m_settingFlag & SETTING_KEY_DELETE_ERROR_MESSAGE_FLAG) + { + jsonContent["message"] = m_Message; + } + return jsonWriter.write(jsonContent); +} + +#ifdef BUILD_C_STYLE_INTERFACE +NotIPAddressType::NotIPAddressType(qs_not_ip_address_t not_ip_address) +{ + if (not_ip_address.source_ip) + SetSourceIP(not_ip_address.source_ip); +} + +qs_not_ip_address_t *NotIPAddressType::toCStyleObj() +{ + qs_not_ip_address_t *not_ip_address = + (qs_not_ip_address_t *) malloc(sizeof(qs_not_ip_address_t)); + qs_list_t *list_source_ip = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(list_source_ip); + std::vector < std::string > sourceIP = GetSourceIP(); + for (std::vector < std::string >::iterator it = sourceIP.begin(); + it != sourceIP.end(); it++) + { + qs_not_ip_address_source_ip_item_t *item = + (qs_not_ip_address_source_ip_item_t *) + malloc(sizeof(qs_not_ip_address_source_ip_item_t)); + int sourceIPLength = it->length(); + if (sourceIPLength > 0) + { + item->content = (char *) malloc(sourceIPLength + 1); + memset(item->content, 0, sourceIPLength + 1); + strncpy(item->content, it->c_str(), sourceIPLength); + } + else + { + item->content = NULL; + } + qs_list_append(&item->node, list_source_ip); + } + not_ip_address->source_ip = list_source_ip; + return not_ip_address; +} + +#endif // BUILD_C_STYLE_INTERFACE + +NotIPAddressType::NotIPAddressType(std::string serializedString) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(serializedString, jsonContent); + if (jsonContent.isMember("source_ip")) + { + std::vector < std::string > vecSourceIP; + for (unsigned i = 0; i < jsonContent["source_ip"].size(); ++i) + { + vecSourceIP.push_back(jsonContent["source_ip"][i].asString()); + } + SetSourceIP(vecSourceIP); + } +} + +std::string NotIPAddressType::Serialize() +{ + Json::Value jsonContent; + Json::FastWriter jsonWriter; + if (m_settingFlag & SETTING_NOT_IP_ADDRESS_SOURCE_IP_FLAG) + { + Json::Value arraySourceIP; + std::vector < std::string > sourceIP = m_SourceIP; + for (std::vector < std::string >::iterator it = sourceIP.begin(); + it != sourceIP.end(); it++) + { + arraySourceIP.append(*it); + } + jsonContent["source_ip"] = arraySourceIP; + } + return jsonWriter.write(jsonContent); +} + +#ifdef BUILD_C_STYLE_INTERFACE +ObjectPartType::ObjectPartType(qs_object_part_t object_part) +{ + if (object_part.created) + SetCreated(object_part.created); + if (object_part.etag) + SetEtag(object_part.etag); + if (object_part.part_number) + SetPartNumber(*object_part.part_number); + if (object_part.size) + SetSize(*object_part.size); +} + +qs_object_part_t *ObjectPartType::toCStyleObj() +{ + qs_object_part_t *object_part = + (qs_object_part_t *) malloc(sizeof(qs_object_part_t)); + int createdLength = 0; + createdLength = GetCreated().length(); + if (createdLength > 0) + { + object_part->created = (char *) malloc(createdLength + 1); + memset(object_part->created, 0, createdLength + 1); + strncpy(object_part->created, GetCreated().c_str(), createdLength); + } + else + { + object_part->created = NULL; + } + int etagLength = 0; + etagLength = GetEtag().length(); + if (etagLength > 0) + { + object_part->etag = (char *) malloc(etagLength + 1); + memset(object_part->etag, 0, etagLength + 1); + strncpy(object_part->etag, GetEtag().c_str(), etagLength); + } + else + { + object_part->etag = NULL; + } + object_part->part_number = (int *) malloc(sizeof(int)); + *object_part->part_number = GetPartNumber(); + object_part->size = (long *) malloc(sizeof(long)); + *object_part->size = GetSize(); + return object_part; +} + +#endif // BUILD_C_STYLE_INTERFACE + +ObjectPartType::ObjectPartType(std::string serializedString) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(serializedString, jsonContent); + if (jsonContent.isMember("created")) + { + SetCreated(jsonContent["created"].asString()); + } + if (jsonContent.isMember("etag")) + { + SetEtag(jsonContent["etag"].asString()); + } + if (jsonContent.isMember("part_number")) + { + SetPartNumber(jsonContent["part_number"].asInt()); + } + if (jsonContent.isMember("size")) + { + SetSize(jsonContent["size"].asInt64()); + } +} + +std::string ObjectPartType::Serialize() +{ + Json::Value jsonContent; + Json::FastWriter jsonWriter; + if (m_settingFlag & SETTING_OBJECT_PART_CREATED_FLAG) + { + jsonContent["created"] = m_Created; + } + if (m_settingFlag & SETTING_OBJECT_PART_ETAG_FLAG) + { + jsonContent["etag"] = m_Etag; + } + if (m_settingFlag & SETTING_OBJECT_PART_PART_NUMBER_FLAG) + { + jsonContent["part_number"] = m_PartNumber; + } + if (m_settingFlag & SETTING_OBJECT_PART_SIZE_FLAG) + { + jsonContent["size"] = (Json::Int64) m_Size; + } + return jsonWriter.write(jsonContent); +} + +#ifdef BUILD_C_STYLE_INTERFACE +OwnerType::OwnerType(qs_owner_t owner) +{ + if (owner.id) + SetID(owner.id); + if (owner.name) + SetName(owner.name); +} + +qs_owner_t *OwnerType::toCStyleObj() +{ + qs_owner_t *owner = (qs_owner_t *) malloc(sizeof(qs_owner_t)); + int idLength = 0; + idLength = GetID().length(); + if (idLength > 0) + { + owner->id = (char *) malloc(idLength + 1); + memset(owner->id, 0, idLength + 1); + strncpy(owner->id, GetID().c_str(), idLength); + } + else + { + owner->id = NULL; + } + int nameLength = 0; + nameLength = GetName().length(); + if (nameLength > 0) + { + owner->name = (char *) malloc(nameLength + 1); + memset(owner->name, 0, nameLength + 1); + strncpy(owner->name, GetName().c_str(), nameLength); + } + else + { + owner->name = NULL; + } + return owner; +} + +#endif // BUILD_C_STYLE_INTERFACE + +OwnerType::OwnerType(std::string serializedString) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(serializedString, jsonContent); + if (jsonContent.isMember("id")) + { + SetID(jsonContent["id"].asString()); + } + if (jsonContent.isMember("name")) + { + SetName(jsonContent["name"].asString()); + } +} + +std::string OwnerType::Serialize() +{ + Json::Value jsonContent; + Json::FastWriter jsonWriter; + if (m_settingFlag & SETTING_OWNER_ID_FLAG) + { + jsonContent["id"] = m_ID; + } + if (m_settingFlag & SETTING_OWNER_NAME_FLAG) + { + jsonContent["name"] = m_Name; + } + return jsonWriter.write(jsonContent); +} + +#ifdef BUILD_C_STYLE_INTERFACE +StatementType::StatementType(qs_statement_t statement) +{ + if (statement.action) + SetAction(statement.action); + if (statement.condition) + SetCondition(*statement.condition); + if (statement.effect) + SetEffect(statement.effect); + if (statement.id) + SetID(statement.id); + if (statement.resource) + SetResource(statement.resource); + if (statement.user) + SetUser(statement.user); +} + +qs_statement_t *StatementType::toCStyleObj() +{ + qs_statement_t *statement = + (qs_statement_t *) malloc(sizeof(qs_statement_t)); + qs_list_t *list_action = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(list_action); + std::vector < std::string > action = GetAction(); + for (std::vector < std::string >::iterator it = action.begin(); + it != action.end(); it++) + { + qs_statement_action_item_t *item = + (qs_statement_action_item_t *) + malloc(sizeof(qs_statement_action_item_t)); + int actionLength = it->length(); + if (actionLength > 0) + { + item->content = (char *) malloc(actionLength + 1); + memset(item->content, 0, actionLength + 1); + strncpy(item->content, it->c_str(), actionLength); + } + else + { + item->content = NULL; + } + qs_list_append(&item->node, list_action); + } + statement->action = list_action; + statement->condition = GetCondition().toCStyleObj(); + int effectLength = 0; + effectLength = GetEffect().length(); + if (effectLength > 0) + { + statement->effect = (char *) malloc(effectLength + 1); + memset(statement->effect, 0, effectLength + 1); + strncpy(statement->effect, GetEffect().c_str(), effectLength); + } + else + { + statement->effect = NULL; + } + int idLength = 0; + idLength = GetID().length(); + if (idLength > 0) + { + statement->id = (char *) malloc(idLength + 1); + memset(statement->id, 0, idLength + 1); + strncpy(statement->id, GetID().c_str(), idLength); + } + else + { + statement->id = NULL; + } + qs_list_t *list_resource = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(list_resource); + std::vector < std::string > resource = GetResource(); + for (std::vector < std::string >::iterator it = resource.begin(); + it != resource.end(); it++) + { + qs_statement_resource_item_t *item = + (qs_statement_resource_item_t *) + malloc(sizeof(qs_statement_resource_item_t)); + int resourceLength = it->length(); + if (resourceLength > 0) + { + item->content = (char *) malloc(resourceLength + 1); + memset(item->content, 0, resourceLength + 1); + strncpy(item->content, it->c_str(), resourceLength); + } + else + { + item->content = NULL; + } + qs_list_append(&item->node, list_resource); + } + statement->resource = list_resource; + qs_list_t *list_user = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(list_user); + std::vector < std::string > user = GetUser(); + for (std::vector < std::string >::iterator it = user.begin(); + it != user.end(); it++) + { + qs_statement_user_item_t *item = + (qs_statement_user_item_t *) + malloc(sizeof(qs_statement_user_item_t)); + int userLength = it->length(); + if (userLength > 0) + { + item->content = (char *) malloc(userLength + 1); + memset(item->content, 0, userLength + 1); + strncpy(item->content, it->c_str(), userLength); + } + else + { + item->content = NULL; + } + qs_list_append(&item->node, list_user); + } + statement->user = list_user; + return statement; +} + +#endif // BUILD_C_STYLE_INTERFACE + +StatementType::StatementType(std::string serializedString) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(serializedString, jsonContent); + if (jsonContent.isMember("action")) + { + std::vector < std::string > vecAction; + for (unsigned i = 0; i < jsonContent["action"].size(); ++i) + { + vecAction.push_back(jsonContent["action"][i].asString()); + } + SetAction(vecAction); + } + if (jsonContent.isMember("condition")) + { + SetCondition(jsonContent["condition"].toStyledString()); + } + if (jsonContent.isMember("effect")) + { + SetEffect(jsonContent["effect"].asString()); + } + if (jsonContent.isMember("id")) + { + SetID(jsonContent["id"].asString()); + } + if (jsonContent.isMember("resource")) + { + std::vector < std::string > vecResource; + for (unsigned i = 0; i < jsonContent["resource"].size(); ++i) + { + vecResource.push_back(jsonContent["resource"][i].asString()); + } + SetResource(vecResource); + } + if (jsonContent.isMember("user")) + { + std::vector < std::string > vecUser; + for (unsigned i = 0; i < jsonContent["user"].size(); ++i) + { + vecUser.push_back(jsonContent["user"][i].asString()); + } + SetUser(vecUser); + } +} + +std::string StatementType::Serialize() +{ + Json::Value jsonContent; + Json::FastWriter jsonWriter; + if (m_settingFlag & SETTING_STATEMENT_ACTION_FLAG) + { + Json::Value arrayAction; + std::vector < std::string > action = m_Action; + for (std::vector < std::string >::iterator it = action.begin(); + it != action.end(); it++) + { + arrayAction.append(*it); + } + jsonContent["action"] = arrayAction; + } + if (m_settingFlag & SETTING_STATEMENT_CONDITION_FLAG) + { + Json::Reader jsonReader; + Json::Value itemJsonValue; + jsonReader.parse(m_Condition.Serialize(), itemJsonValue); + jsonContent["condition"] = itemJsonValue; + } + if (m_settingFlag & SETTING_STATEMENT_EFFECT_FLAG) + { + jsonContent["effect"] = m_Effect; + } + if (m_settingFlag & SETTING_STATEMENT_ID_FLAG) + { + jsonContent["id"] = m_ID; + } + if (m_settingFlag & SETTING_STATEMENT_RESOURCE_FLAG) + { + Json::Value arrayResource; + std::vector < std::string > resource = m_Resource; + for (std::vector < std::string >::iterator it = resource.begin(); + it != resource.end(); it++) + { + arrayResource.append(*it); + } + jsonContent["resource"] = arrayResource; + } + if (m_settingFlag & SETTING_STATEMENT_USER_FLAG) + { + Json::Value arrayUser; + std::vector < std::string > user = m_User; + for (std::vector < std::string >::iterator it = user.begin(); + it != user.end(); it++) + { + arrayUser.append(*it); + } + jsonContent["user"] = arrayUser; + } + return jsonWriter.write(jsonContent); +} + +#ifdef BUILD_C_STYLE_INTERFACE +StringLikeType::StringLikeType(qs_string_like_t string_like) +{ + if (string_like.referer) + SetReferer(string_like.referer); +} + +qs_string_like_t *StringLikeType::toCStyleObj() +{ + qs_string_like_t *string_like = + (qs_string_like_t *) malloc(sizeof(qs_string_like_t)); + qs_list_t *list_referer = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(list_referer); + std::vector < std::string > referer = GetReferer(); + for (std::vector < std::string >::iterator it = referer.begin(); + it != referer.end(); it++) + { + qs_string_like_referer_item_t *item = + (qs_string_like_referer_item_t *) + malloc(sizeof(qs_string_like_referer_item_t)); + int refererLength = it->length(); + if (refererLength > 0) + { + item->content = (char *) malloc(refererLength + 1); + memset(item->content, 0, refererLength + 1); + strncpy(item->content, it->c_str(), refererLength); + } + else + { + item->content = NULL; + } + qs_list_append(&item->node, list_referer); + } + string_like->referer = list_referer; + return string_like; +} + +#endif // BUILD_C_STYLE_INTERFACE + +StringLikeType::StringLikeType(std::string serializedString) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(serializedString, jsonContent); + if (jsonContent.isMember("Referer")) + { + std::vector < std::string > vecReferer; + for (unsigned i = 0; i < jsonContent["Referer"].size(); ++i) + { + vecReferer.push_back(jsonContent["Referer"][i].asString()); + } + SetReferer(vecReferer); + } +} + +std::string StringLikeType::Serialize() +{ + Json::Value jsonContent; + Json::FastWriter jsonWriter; + if (m_settingFlag & SETTING_STRING_LIKE_REFERER_FLAG) + { + Json::Value arrayReferer; + std::vector < std::string > referer = m_Referer; + for (std::vector < std::string >::iterator it = referer.begin(); + it != referer.end(); it++) + { + arrayReferer.append(*it); + } + jsonContent["Referer"] = arrayReferer; + } + return jsonWriter.write(jsonContent); +} + +#ifdef BUILD_C_STYLE_INTERFACE +StringNotLikeType::StringNotLikeType(qs_string_not_like_t string_not_like) +{ + if (string_not_like.referer) + SetReferer(string_not_like.referer); +} + +qs_string_not_like_t *StringNotLikeType::toCStyleObj() +{ + qs_string_not_like_t *string_not_like = + (qs_string_not_like_t *) malloc(sizeof(qs_string_not_like_t)); + qs_list_t *list_referer = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(list_referer); + std::vector < std::string > referer = GetReferer(); + for (std::vector < std::string >::iterator it = referer.begin(); + it != referer.end(); it++) + { + qs_string_not_like_referer_item_t *item = + (qs_string_not_like_referer_item_t *) + malloc(sizeof(qs_string_not_like_referer_item_t)); + int refererLength = it->length(); + if (refererLength > 0) + { + item->content = (char *) malloc(refererLength + 1); + memset(item->content, 0, refererLength + 1); + strncpy(item->content, it->c_str(), refererLength); + } + else + { + item->content = NULL; + } + qs_list_append(&item->node, list_referer); + } + string_not_like->referer = list_referer; + return string_not_like; +} + +#endif // BUILD_C_STYLE_INTERFACE + +StringNotLikeType::StringNotLikeType(std::string serializedString) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(serializedString, jsonContent); + if (jsonContent.isMember("Referer")) + { + std::vector < std::string > vecReferer; + for (unsigned i = 0; i < jsonContent["Referer"].size(); ++i) + { + vecReferer.push_back(jsonContent["Referer"][i].asString()); + } + SetReferer(vecReferer); + } +} + +std::string StringNotLikeType::Serialize() +{ + Json::Value jsonContent; + Json::FastWriter jsonWriter; + if (m_settingFlag & SETTING_STRING_NOT_LIKE_REFERER_FLAG) + { + Json::Value arrayReferer; + std::vector < std::string > referer = m_Referer; + for (std::vector < std::string >::iterator it = referer.begin(); + it != referer.end(); it++) + { + arrayReferer.append(*it); + } + jsonContent["Referer"] = arrayReferer; + } + return jsonWriter.write(jsonContent); +} + +#ifdef BUILD_C_STYLE_INTERFACE +UploadsType::UploadsType(qs_uploads_t uploads) +{ + if (uploads.created) + SetCreated(uploads.created); + if (uploads.key) + SetKey(uploads.key); + if (uploads.upload_id) + SetUploadID(uploads.upload_id); +} + +qs_uploads_t *UploadsType::toCStyleObj() +{ + qs_uploads_t *uploads = (qs_uploads_t *) malloc(sizeof(qs_uploads_t)); + int createdLength = 0; + createdLength = GetCreated().length(); + if (createdLength > 0) + { + uploads->created = (char *) malloc(createdLength + 1); + memset(uploads->created, 0, createdLength + 1); + strncpy(uploads->created, GetCreated().c_str(), createdLength); + } + else + { + uploads->created = NULL; + } + int keyLength = 0; + keyLength = GetKey().length(); + if (keyLength > 0) + { + uploads->key = (char *) malloc(keyLength + 1); + memset(uploads->key, 0, keyLength + 1); + strncpy(uploads->key, GetKey().c_str(), keyLength); + } + else + { + uploads->key = NULL; + } + int uploadIDLength = 0; + uploadIDLength = GetUploadID().length(); + if (uploadIDLength > 0) + { + uploads->upload_id = (char *) malloc(uploadIDLength + 1); + memset(uploads->upload_id, 0, uploadIDLength + 1); + strncpy(uploads->upload_id, GetUploadID().c_str(), uploadIDLength); + } + else + { + uploads->upload_id = NULL; + } + return uploads; +} + +#endif // BUILD_C_STYLE_INTERFACE + +UploadsType::UploadsType(std::string serializedString) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + jsonReader.parse(serializedString, jsonContent); + if (jsonContent.isMember("created")) + { + SetCreated(jsonContent["created"].asString()); + } + if (jsonContent.isMember("key")) + { + SetKey(jsonContent["key"].asString()); + } + if (jsonContent.isMember("upload_id")) + { + SetUploadID(jsonContent["upload_id"].asString()); + } +} + +std::string UploadsType::Serialize() +{ + Json::Value jsonContent; + Json::FastWriter jsonWriter; + if (m_settingFlag & SETTING_UPLOADS_CREATED_FLAG) + { + jsonContent["created"] = m_Created; + } + if (m_settingFlag & SETTING_UPLOADS_KEY_FLAG) + { + jsonContent["key"] = m_Key; + } + if (m_settingFlag & SETTING_UPLOADS_UPLOAD_ID_FLAG) + { + jsonContent["upload_id"] = m_UploadID; + } + return jsonWriter.write(jsonContent); +} diff --git a/src/service/service_with_c_style/QingStorCStyle.cpp b/src/service/service_with_c_style/QingStorCStyle.cpp new file mode 100644 index 0000000..ffd7b16 --- /dev/null +++ b/src/service/service_with_c_style/QingStorCStyle.cpp @@ -0,0 +1,3679 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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 "QingStor.h" +#include "Bucket.h" +#include "QsConfig.h" +#include "service_with_c_style/QingStorCStyle.h" +#include "utils/QsStream.h" +#include "external/plog/Log.h" + +using namespace QingStor; + +void qs_init_sdk(const char *logfile_path, LogLevel qs_log_level, + unsigned int init_and_cleanup_curl) +{ + QingStor::SDKOptions sdkOptions; + sdkOptions.logLevel = qs_log_level; + sdkOptions.logPath = logfile_path; + if (!init_and_cleanup_curl) + { + sdkOptions.initAndCleanupCurl = false; + } + else + { + sdkOptions.initAndCleanupCurl = true; + } + QingStor::InitializeSDK(sdkOptions); +} + +void qs_shutdown_sdk(unsigned int init_and_cleanup_curl) +{ + QingStor::SDKOptions sdkOptions; + if (!init_and_cleanup_curl) + { + sdkOptions.initAndCleanupCurl = false; + } + else + { + sdkOptions.initAndCleanupCurl = true; + } + QingStor::ShutdownSDK(sdkOptions); +} + +qs_context_handle qs_create_service_with_configfile(const char *qs_configfile, + const char *qs_bucket_name, + const char *qs_bucket_zone) +{ + qs_context_handle context_hdl; + QsConfig qsConfig; + qsConfig.LoadConfigFile(qs_configfile); + context_hdl.pQsService = new QingStorService(qsConfig); + context_hdl.pQsBucket = + new Bucket(qsConfig, qs_bucket_name, qs_bucket_zone); + return context_hdl; +} + +QS_SDK_API qs_context_handle qs_create_service(qs_config_t + qs_config, + const char + *qs_bucket_name, + const char *qs_bucket_zone) +{ + qs_context_handle context_hdl; + QsConfig qsConfig; + if (qs_config.additional_user_agent) + qsConfig.additionalUserAgent = qs_config.additional_user_agent; + if (qs_config.access_key_id) + qsConfig.accessKeyId = qs_config.access_key_id; + if (qs_config.secret_access_key) + qsConfig.secretAccessKey = qs_config.secret_access_key; + if (qs_config.host) + qsConfig.host = qs_config.host; + if (qs_config.protocol) + qsConfig.protocol = qs_config.protocol; + if (0 < qs_config.port && 65535 > qs_config.port) + { + qsConfig.port = qs_config.port; + } + if (0 <= qs_config.conn_retries && 10 > qs_config.conn_retries) + { + qsConfig.connectionRetries = qs_config.conn_retries; + } + if (0 <= qs_config.timeout_period && 100 > qs_config.timeout_period) + { + qsConfig.timeOutPeriod = qs_config.timeout_period; + } + context_hdl.pQsService = new QingStorService(qsConfig); + context_hdl.pQsBucket = + new Bucket(qsConfig, qs_bucket_name, qs_bucket_zone); + return context_hdl; +} + +void qs_release_service(qs_context_handle context_hdl) +{ + if (context_hdl.pQsService) + { + QingStorService *pQsService2Delete = + (QingStorService *) context_hdl.pQsService; + delete pQsService2Delete; + } + if (context_hdl.pQsBucket) + { + Bucket *pBucket2Delete = (Bucket *) context_hdl.pQsBucket; + delete pBucket2Delete; + } +} + +void qs_set_error_info(qs_error_info_t * err_info, ResponseErrorInfo & errInfo) +{ + int codeLength = errInfo.code.length(); + if (codeLength > 0) + { + err_info->code = (char *) malloc(codeLength + 1); + memset(err_info->code, 0, codeLength + 1); + strncpy(err_info->code, errInfo.code.c_str(), codeLength); + } + int messageLength = errInfo.message.length(); + if (messageLength > 0) + { + err_info->message = (char *) malloc(messageLength + 1); + memset(err_info->message, 0, messageLength + 1); + strncpy(err_info->message, errInfo.message.c_str(), messageLength); + } + int requestIDLength = errInfo.requestID.length(); + if (requestIDLength > 0) + { + err_info->request_id = (char *) malloc(requestIDLength + 1); + memset(err_info->request_id, 0, requestIDLength + 1); + strncpy(err_info->request_id, errInfo.requestID.c_str(), + requestIDLength); + } + int urlLength = errInfo.url.length(); + if (urlLength > 0) + { + err_info->url = (char *) malloc(urlLength + 1); + memset(err_info->url, 0, urlLength + 1); + strncpy(err_info->url, errInfo.url.c_str(), urlLength); + } +} + +void qs_release_error_info(qs_error_info_t * err_info) +{ + if (!err_info) + { + return; + } + if (err_info->code) + { + free(err_info->code); + } + if (err_info->message) + { + free(err_info->message); + } + if (err_info->request_id) + { + free(err_info->request_id); + } + if (err_info->url) + { + free(err_info->url); + } +} + +void qs_init_error_info(qs_error_info_t * err_info) +{ + err_info->code = NULL; + err_info->message = NULL; + err_info->request_id = NULL; + err_info->url = NULL; +} + +// list_bucketsInput init function. +void init_list_buckets_input(qs_list_buckets_input_t * input) +{ + input->location = NULL; + return; +} + +// list_bucketsoutput init function. +void init_list_buckets_output(qs_list_buckets_output_t * output) +{ + output->buckets = NULL; + output->count = NULL; + qs_init_error_info(&output->error_info); + return; +} + +// list_buckets Output release function. +void release_list_buckets_output(qs_list_buckets_output_t * output) +{ + if (output->buckets) + { + qs_bucket_item_t *item = NULL; + qs_bucket_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_bucket_item_t, item, output->buckets) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + release_bucket(item->content); + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(output->buckets); + } + if (output->count) + { + free(output->count); + } + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_list_buckets(qs_list_buckets_input_t * input, + qs_list_buckets_output_t * output, + qs_context_handle context_hdl) +{ + //init class ListBucketsinputCpp + ListBucketsInput inputCpp; + ListBucketsOutput outputCpp; + // packer cpp input + if (input->location) + { + inputCpp.SetLocation(input->location); + } + // init output + init_list_buckets_output(output); + // call cpp op + QingStorService *qsService = (QingStorService *) (context_hdl.pQsService); + QsError err = qsService->ListBuckets(inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->buckets = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(output->buckets); + std::vector < BucketType > buckets = outputCpp.GetBuckets(); + for (std::vector < BucketType >::iterator it = buckets.begin(); + it != buckets.end(); it++) + { + qs_bucket_item_t *item = + (qs_bucket_item_t *) malloc(sizeof(qs_bucket_item_t)); + item->content = it->toCStyleObj(); + qs_list_append(&item->node, output->buckets); + } + output->count = (int *) malloc(sizeof(int)); + *output->count = outputCpp.GetCount(); + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// delete_bucketInput init function. +void init_delete_bucket_input(qs_delete_bucket_input_t * input) +{ + // nothing to do; + return; +} + +// delete_bucketoutput init function. +void init_delete_bucket_output(qs_delete_bucket_output_t * output) +{ + qs_init_error_info(&output->error_info); + return; +} + +// delete_bucket Output release function. +void release_delete_bucket_output(qs_delete_bucket_output_t * output) +{ + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_delete_bucket(qs_delete_bucket_input_t * input, + qs_delete_bucket_output_t * output, + qs_context_handle context_hdl) +{ + //init class DeleteBucketinputCpp + DeleteBucketInput inputCpp; + DeleteBucketOutput outputCpp; + // packer cpp input + // init output + init_delete_bucket_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->DeleteBucket(inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// delete_bucket_corsInput init function. +void init_delete_bucket_cors_input(qs_delete_bucket_cors_input_t * input) +{ + // nothing to do; + return; +} + +// delete_bucket_corsoutput init function. +void init_delete_bucket_cors_output(qs_delete_bucket_cors_output_t * output) +{ + qs_init_error_info(&output->error_info); + return; +} + +// delete_bucket_cors Output release function. +void release_delete_bucket_cors_output(qs_delete_bucket_cors_output_t * output) +{ + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_delete_bucket_cors(qs_delete_bucket_cors_input_t * input, + qs_delete_bucket_cors_output_t * output, + qs_context_handle context_hdl) +{ + //init class DeleteBucketCORSinputCpp + DeleteBucketCORSInput inputCpp; + DeleteBucketCORSOutput outputCpp; + // packer cpp input + // init output + init_delete_bucket_cors_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->DeleteBucketCORS(inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// delete_bucket_external_mirrorInput init function. +void +init_delete_bucket_external_mirror_input +(qs_delete_bucket_external_mirror_input_t * input) +{ + // nothing to do; + return; +} + +// delete_bucket_external_mirroroutput init function. +void +init_delete_bucket_external_mirror_output +(qs_delete_bucket_external_mirror_output_t * output) +{ + qs_init_error_info(&output->error_info); + return; +} + +// delete_bucket_external_mirror Output release function. +void +release_delete_bucket_external_mirror_output +(qs_delete_bucket_external_mirror_output_t * output) +{ + qs_release_error_info(&output->error_info); + return; +} + +QsError +qs_delete_bucket_external_mirror(qs_delete_bucket_external_mirror_input_t * + input, + qs_delete_bucket_external_mirror_output_t * + output, qs_context_handle context_hdl) +{ + //init class DeleteBucketExternalMirrorinputCpp + DeleteBucketExternalMirrorInput inputCpp; + DeleteBucketExternalMirrorOutput outputCpp; + // packer cpp input + // init output + init_delete_bucket_external_mirror_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->DeleteBucketExternalMirror(inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// delete_bucket_policyInput init function. +void init_delete_bucket_policy_input(qs_delete_bucket_policy_input_t * input) +{ + // nothing to do; + return; +} + +// delete_bucket_policyoutput init function. +void init_delete_bucket_policy_output(qs_delete_bucket_policy_output_t * output) +{ + qs_init_error_info(&output->error_info); + return; +} + +// delete_bucket_policy Output release function. +void release_delete_bucket_policy_output(qs_delete_bucket_policy_output_t * + output) +{ + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_delete_bucket_policy(qs_delete_bucket_policy_input_t * input, + qs_delete_bucket_policy_output_t * output, + qs_context_handle context_hdl) +{ + //init class DeleteBucketPolicyinputCpp + DeleteBucketPolicyInput inputCpp; + DeleteBucketPolicyOutput outputCpp; + // packer cpp input + // init output + init_delete_bucket_policy_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->DeleteBucketPolicy(inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// delete_multiple_objectsInput init function. +void init_delete_multiple_objects_input(qs_delete_multiple_objects_input_t * + input) +{ + input->content_md5 = NULL; + input->objects = NULL; + input->quiet = NULL; + return; +} + +// delete_multiple_objectsoutput init function. +void init_delete_multiple_objects_output(qs_delete_multiple_objects_output_t * + output) +{ + output->deleted = NULL; + output->errors = NULL; + qs_init_error_info(&output->error_info); + return; +} + +// delete_multiple_objects Output release function. +void release_delete_multiple_objects_output(qs_delete_multiple_objects_output_t + * output) +{ + if (output->deleted) + { + qs_key_item_t *item = NULL; + qs_key_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_key_item_t, item, output->deleted) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + release_key(item->content); + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(output->deleted); + } + if (output->errors) + { + qs_key_delete_error_item_t *item = NULL; + qs_key_delete_error_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_key_delete_error_item_t, item, output->errors) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + release_key_delete_error(item->content); + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(output->errors); + } + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_delete_multiple_objects(qs_delete_multiple_objects_input_t * input, + qs_delete_multiple_objects_output_t * output, + qs_context_handle context_hdl) +{ + //init class DeleteMultipleObjectsinputCpp + DeleteMultipleObjectsInput inputCpp; + DeleteMultipleObjectsOutput outputCpp; + // packer cpp input + if (input->content_md5) + { + inputCpp.SetContentMD5(input->content_md5); + } + if (input->objects) + { + //qs_list_t list_objects; + //qs_list_init(list_objects); + std::vector < KeyType > Objects; + qs_key_item_t *item; + qs_list_for_each_entry(qs_key_item_t, item, input->objects) + { + Objects.push_back(*item->content); + } + inputCpp.SetObjects(Objects); + } + if (input->quiet) + { + inputCpp.SetQuiet(*input->quiet); + } + // init output + init_delete_multiple_objects_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->DeleteMultipleObjects(inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->deleted = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(output->deleted); + std::vector < KeyType > deleted = outputCpp.GetDeleted(); + for (std::vector < KeyType >::iterator it = deleted.begin(); + it != deleted.end(); it++) + { + qs_key_item_t *item = + (qs_key_item_t *) malloc(sizeof(qs_key_item_t)); + item->content = it->toCStyleObj(); + qs_list_append(&item->node, output->deleted); + } + output->errors = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(output->errors); + std::vector < KeyDeleteErrorType > errors = outputCpp.GetErrors(); + for (std::vector < KeyDeleteErrorType >::iterator it = errors.begin(); + it != errors.end(); it++) + { + qs_key_delete_error_item_t *item = + (qs_key_delete_error_item_t *) + malloc(sizeof(qs_key_delete_error_item_t)); + item->content = it->toCStyleObj(); + qs_list_append(&item->node, output->errors); + } + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// get_bucket_aclInput init function. +void init_get_bucket_acl_input(qs_get_bucket_acl_input_t * input) +{ + // nothing to do; + return; +} + +// get_bucket_acloutput init function. +void init_get_bucket_acl_output(qs_get_bucket_acl_output_t * output) +{ + output->acl = NULL; + output->owner = NULL; + qs_init_error_info(&output->error_info); + return; +} + +// get_bucket_acl Output release function. +void release_get_bucket_acl_output(qs_get_bucket_acl_output_t * output) +{ + if (output->acl) + { + qs_acl_item_t *item = NULL; + qs_acl_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_acl_item_t, item, output->acl) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + release_acl(item->content); + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(output->acl); + } + if (output->owner) + { + release_owner(output->owner); + free(output->owner); + } + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_get_bucket_acl(qs_get_bucket_acl_input_t * input, + qs_get_bucket_acl_output_t * output, + qs_context_handle context_hdl) +{ + //init class GetBucketACLinputCpp + GetBucketACLInput inputCpp; + GetBucketACLOutput outputCpp; + // packer cpp input + // init output + init_get_bucket_acl_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->GetBucketACL(inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->acl = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(output->acl); + std::vector < ACLType > acl = outputCpp.GetACL(); + for (std::vector < ACLType >::iterator it = acl.begin(); + it != acl.end(); it++) + { + qs_acl_item_t *item = + (qs_acl_item_t *) malloc(sizeof(qs_acl_item_t)); + item->content = it->toCStyleObj(); + qs_list_append(&item->node, output->acl); + } + output->owner = outputCpp.GetOwner().toCStyleObj(); + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// get_bucket_corsInput init function. +void init_get_bucket_cors_input(qs_get_bucket_cors_input_t * input) +{ + // nothing to do; + return; +} + +// get_bucket_corsoutput init function. +void init_get_bucket_cors_output(qs_get_bucket_cors_output_t * output) +{ + output->cors_rules = NULL; + qs_init_error_info(&output->error_info); + return; +} + +// get_bucket_cors Output release function. +void release_get_bucket_cors_output(qs_get_bucket_cors_output_t * output) +{ + if (output->cors_rules) + { + qs_cors_rule_item_t *item = NULL; + qs_cors_rule_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_cors_rule_item_t, item, output->cors_rules) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + release_cors_rule(item->content); + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(output->cors_rules); + } + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_get_bucket_cors(qs_get_bucket_cors_input_t * input, + qs_get_bucket_cors_output_t * output, + qs_context_handle context_hdl) +{ + //init class GetBucketCORSinputCpp + GetBucketCORSInput inputCpp; + GetBucketCORSOutput outputCpp; + // packer cpp input + // init output + init_get_bucket_cors_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->GetBucketCORS(inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->cors_rules = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(output->cors_rules); + std::vector < CORSRuleType > corsRules = outputCpp.GetCORSRules(); + for (std::vector < CORSRuleType >::iterator it = corsRules.begin(); + it != corsRules.end(); it++) + { + qs_cors_rule_item_t *item = + (qs_cors_rule_item_t *) malloc(sizeof(qs_cors_rule_item_t)); + item->content = it->toCStyleObj(); + qs_list_append(&item->node, output->cors_rules); + } + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// get_bucket_external_mirrorInput init function. +void init_get_bucket_external_mirror_input(qs_get_bucket_external_mirror_input_t + * input) +{ + // nothing to do; + return; +} + +// get_bucket_external_mirroroutput init function. +void +init_get_bucket_external_mirror_output(qs_get_bucket_external_mirror_output_t * + output) +{ + output->source_site = NULL; + qs_init_error_info(&output->error_info); + return; +} + +// get_bucket_external_mirror Output release function. +void +release_get_bucket_external_mirror_output(qs_get_bucket_external_mirror_output_t + * output) +{ + if (output->source_site) + { + free(output->source_site); + } + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_get_bucket_external_mirror(qs_get_bucket_external_mirror_input_t * + input, + qs_get_bucket_external_mirror_output_t * + output, qs_context_handle context_hdl) +{ + //init class GetBucketExternalMirrorinputCpp + GetBucketExternalMirrorInput inputCpp; + GetBucketExternalMirrorOutput outputCpp; + // packer cpp input + // init output + init_get_bucket_external_mirror_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->GetBucketExternalMirror(inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + int SourceSiteLength = outputCpp.GetSourceSite().length(); + if (SourceSiteLength > 0) + { + output->source_site = (char *) malloc(SourceSiteLength + 1); + memset(output->source_site, 0, SourceSiteLength + 1); + strncpy(output->source_site, outputCpp.GetSourceSite().c_str(), + SourceSiteLength); + } + else + { + output->source_site = NULL; + } + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// get_bucket_policyInput init function. +void init_get_bucket_policy_input(qs_get_bucket_policy_input_t * input) +{ + // nothing to do; + return; +} + +// get_bucket_policyoutput init function. +void init_get_bucket_policy_output(qs_get_bucket_policy_output_t * output) +{ + output->statement = NULL; + qs_init_error_info(&output->error_info); + return; +} + +// get_bucket_policy Output release function. +void release_get_bucket_policy_output(qs_get_bucket_policy_output_t * output) +{ + if (output->statement) + { + qs_statement_item_t *item = NULL; + qs_statement_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_statement_item_t, item, output->statement) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + release_statement(item->content); + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(output->statement); + } + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_get_bucket_policy(qs_get_bucket_policy_input_t * input, + qs_get_bucket_policy_output_t * output, + qs_context_handle context_hdl) +{ + //init class GetBucketPolicyinputCpp + GetBucketPolicyInput inputCpp; + GetBucketPolicyOutput outputCpp; + // packer cpp input + // init output + init_get_bucket_policy_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->GetBucketPolicy(inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->statement = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(output->statement); + std::vector < StatementType > statement = outputCpp.GetStatement(); + for (std::vector < StatementType >::iterator it = statement.begin(); + it != statement.end(); it++) + { + qs_statement_item_t *item = + (qs_statement_item_t *) malloc(sizeof(qs_statement_item_t)); + item->content = it->toCStyleObj(); + qs_list_append(&item->node, output->statement); + } + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// get_bucket_statisticsInput init function. +void init_get_bucket_statistics_input(qs_get_bucket_statistics_input_t * input) +{ + // nothing to do; + return; +} + +// get_bucket_statisticsoutput init function. +void init_get_bucket_statistics_output(qs_get_bucket_statistics_output_t * + output) +{ + output->count = NULL; + output->created = NULL; + output->location = NULL; + output->name = NULL; + output->size = NULL; + output->status = NULL; + output->url = NULL; + qs_init_error_info(&output->error_info); + return; +} + +// get_bucket_statistics Output release function. +void release_get_bucket_statistics_output(qs_get_bucket_statistics_output_t * + output) +{ + if (output->count) + { + free(output->count); + } + if (output->created) + { + free(output->created); + } + if (output->location) + { + free(output->location); + } + if (output->name) + { + free(output->name); + } + if (output->size) + { + free(output->size); + } + if (output->status) + { + free(output->status); + } + if (output->url) + { + free(output->url); + } + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_get_bucket_statistics(qs_get_bucket_statistics_input_t * input, + qs_get_bucket_statistics_output_t * output, + qs_context_handle context_hdl) +{ + //init class GetBucketStatisticsinputCpp + GetBucketStatisticsInput inputCpp; + GetBucketStatisticsOutput outputCpp; + // packer cpp input + // init output + init_get_bucket_statistics_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->GetBucketStatistics(inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->count = (long *) malloc(sizeof(long)); + *output->count = outputCpp.GetCount(); + int CreatedLength = outputCpp.GetCreated().length(); + if (CreatedLength > 0) + { + output->created = (char *) malloc(CreatedLength + 1); + memset(output->created, 0, CreatedLength + 1); + strncpy(output->created, outputCpp.GetCreated().c_str(), + CreatedLength); + } + else + { + output->created = NULL; + } + int LocationLength = outputCpp.GetLocation().length(); + if (LocationLength > 0) + { + output->location = (char *) malloc(LocationLength + 1); + memset(output->location, 0, LocationLength + 1); + strncpy(output->location, outputCpp.GetLocation().c_str(), + LocationLength); + } + else + { + output->location = NULL; + } + int NameLength = outputCpp.GetName().length(); + if (NameLength > 0) + { + output->name = (char *) malloc(NameLength + 1); + memset(output->name, 0, NameLength + 1); + strncpy(output->name, outputCpp.GetName().c_str(), NameLength); + } + else + { + output->name = NULL; + } + output->size = (long *) malloc(sizeof(long)); + *output->size = outputCpp.GetSize(); + int StatusLength = outputCpp.GetStatus().length(); + if (StatusLength > 0) + { + output->status = (char *) malloc(StatusLength + 1); + memset(output->status, 0, StatusLength + 1); + strncpy(output->status, outputCpp.GetStatus().c_str(), + StatusLength); + } + else + { + output->status = NULL; + } + int URLLength = outputCpp.GetURL().length(); + if (URLLength > 0) + { + output->url = (char *) malloc(URLLength + 1); + memset(output->url, 0, URLLength + 1); + strncpy(output->url, outputCpp.GetURL().c_str(), URLLength); + } + else + { + output->url = NULL; + } + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// head_bucketInput init function. +void init_head_bucket_input(qs_head_bucket_input_t * input) +{ + // nothing to do; + return; +} + +// head_bucketoutput init function. +void init_head_bucket_output(qs_head_bucket_output_t * output) +{ + qs_init_error_info(&output->error_info); + return; +} + +// head_bucket Output release function. +void release_head_bucket_output(qs_head_bucket_output_t * output) +{ + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_head_bucket(qs_head_bucket_input_t * input, + qs_head_bucket_output_t * output, + qs_context_handle context_hdl) +{ + //init class HeadBucketinputCpp + HeadBucketInput inputCpp; + HeadBucketOutput outputCpp; + // packer cpp input + // init output + init_head_bucket_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->HeadBucket(inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// list_multipart_uploadsInput init function. +void init_list_multipart_uploads_input(qs_list_multipart_uploads_input_t * + input) +{ + input->delimiter = NULL; + input->key_marker = NULL; + input->limit = NULL; + input->prefix = NULL; + input->upload_id_marker = NULL; + return; +} + +// list_multipart_uploadsoutput init function. +void init_list_multipart_uploads_output(qs_list_multipart_uploads_output_t * + output) +{ + output->common_prefixes = NULL; + output->delimiter = NULL; + output->limit = NULL; + output->marker = NULL; + output->name = NULL; + output->next_key_marker = NULL; + output->next_upload_id_marker = NULL; + output->prefix = NULL; + output->uploads = NULL; + qs_init_error_info(&output->error_info); + return; +} + +// list_multipart_uploads Output release function. +void release_list_multipart_uploads_output(qs_list_multipart_uploads_output_t * + output) +{ + if (output->common_prefixes) + { + qs_string_item_t *item = NULL; + qs_string_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_string_item_t, item, output->common_prefixes) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(output->common_prefixes); + } + if (output->delimiter) + { + free(output->delimiter); + } + if (output->limit) + { + free(output->limit); + } + if (output->marker) + { + free(output->marker); + } + if (output->name) + { + free(output->name); + } + if (output->next_key_marker) + { + free(output->next_key_marker); + } + if (output->next_upload_id_marker) + { + free(output->next_upload_id_marker); + } + if (output->prefix) + { + free(output->prefix); + } + if (output->uploads) + { + qs_uploads_item_t *item = NULL; + qs_uploads_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_uploads_item_t, item, output->uploads) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + release_uploads(item->content); + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(output->uploads); + } + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_list_multipart_uploads(qs_list_multipart_uploads_input_t * input, + qs_list_multipart_uploads_output_t * output, + qs_context_handle context_hdl) +{ + //init class ListMultipartUploadsinputCpp + ListMultipartUploadsInput inputCpp; + ListMultipartUploadsOutput outputCpp; + // packer cpp input + if (input->delimiter) + { + inputCpp.SetDelimiter(input->delimiter); + } + if (input->key_marker) + { + inputCpp.SetKeyMarker(input->key_marker); + } + if (input->limit) + { + inputCpp.SetLimit(*input->limit); + } + if (input->prefix) + { + inputCpp.SetPrefix(input->prefix); + } + if (input->upload_id_marker) + { + inputCpp.SetUploadIDMarker(input->upload_id_marker); + } + // init output + init_list_multipart_uploads_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->ListMultipartUploads(inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->common_prefixes = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(output->common_prefixes); + std::vector < std::string > commonPrefixes = + outputCpp.GetCommonPrefixes(); + for (std::vector < std::string >::iterator it = commonPrefixes.begin(); + it != commonPrefixes.end(); it++) + { + qs_string_item_t *item = + (qs_string_item_t *) malloc(sizeof(qs_string_item_t)); + int CommonPrefixesLength = it->length(); + if (CommonPrefixesLength > 0) + { + item->content = (char *) malloc(CommonPrefixesLength + 1); + memset(item->content, 0, CommonPrefixesLength + 1); + item->content = (char *) malloc(CommonPrefixesLength + 1); + strncpy(item->content, it->c_str(), CommonPrefixesLength); + } + else + { + item->content = NULL; + } + qs_list_append(&item->node, output->common_prefixes); + } + int DelimiterLength = outputCpp.GetDelimiter().length(); + if (DelimiterLength > 0) + { + output->delimiter = (char *) malloc(DelimiterLength + 1); + memset(output->delimiter, 0, DelimiterLength + 1); + strncpy(output->delimiter, outputCpp.GetDelimiter().c_str(), + DelimiterLength); + } + else + { + output->delimiter = NULL; + } + output->limit = (int *) malloc(sizeof(int)); + *output->limit = outputCpp.GetLimit(); + int MarkerLength = outputCpp.GetMarker().length(); + if (MarkerLength > 0) + { + output->marker = (char *) malloc(MarkerLength + 1); + memset(output->marker, 0, MarkerLength + 1); + strncpy(output->marker, outputCpp.GetMarker().c_str(), + MarkerLength); + } + else + { + output->marker = NULL; + } + int NameLength = outputCpp.GetName().length(); + if (NameLength > 0) + { + output->name = (char *) malloc(NameLength + 1); + memset(output->name, 0, NameLength + 1); + strncpy(output->name, outputCpp.GetName().c_str(), NameLength); + } + else + { + output->name = NULL; + } + int NextKeyMarkerLength = outputCpp.GetNextKeyMarker().length(); + if (NextKeyMarkerLength > 0) + { + output->next_key_marker = (char *) malloc(NextKeyMarkerLength + 1); + memset(output->next_key_marker, 0, NextKeyMarkerLength + 1); + strncpy(output->next_key_marker, + outputCpp.GetNextKeyMarker().c_str(), NextKeyMarkerLength); + } + else + { + output->next_key_marker = NULL; + } + int NextUploadIDMarkerLength = + outputCpp.GetNextUploadIDMarker().length(); + if (NextUploadIDMarkerLength > 0) + { + output->next_upload_id_marker = + (char *) malloc(NextUploadIDMarkerLength + 1); + memset(output->next_upload_id_marker, 0, + NextUploadIDMarkerLength + 1); + strncpy(output->next_upload_id_marker, + outputCpp.GetNextUploadIDMarker().c_str(), + NextUploadIDMarkerLength); + } + else + { + output->next_upload_id_marker = NULL; + } + int PrefixLength = outputCpp.GetPrefix().length(); + if (PrefixLength > 0) + { + output->prefix = (char *) malloc(PrefixLength + 1); + memset(output->prefix, 0, PrefixLength + 1); + strncpy(output->prefix, outputCpp.GetPrefix().c_str(), + PrefixLength); + } + else + { + output->prefix = NULL; + } + output->uploads = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(output->uploads); + std::vector < UploadsType > uploads = outputCpp.GetUploads(); + for (std::vector < UploadsType >::iterator it = uploads.begin(); + it != uploads.end(); it++) + { + qs_uploads_item_t *item = + (qs_uploads_item_t *) malloc(sizeof(qs_uploads_item_t)); + item->content = it->toCStyleObj(); + qs_list_append(&item->node, output->uploads); + } + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// list_objectsInput init function. +void init_list_objects_input(qs_list_objects_input_t * input) +{ + input->delimiter = NULL; + input->limit = NULL; + input->marker = NULL; + input->prefix = NULL; + return; +} + +// list_objectsoutput init function. +void init_list_objects_output(qs_list_objects_output_t * output) +{ + output->common_prefixes = NULL; + output->delimiter = NULL; + output->keys = NULL; + output->limit = NULL; + output->marker = NULL; + output->name = NULL; + output->next_marker = NULL; + output->owner = NULL; + output->prefix = NULL; + qs_init_error_info(&output->error_info); + return; +} + +// list_objects Output release function. +void release_list_objects_output(qs_list_objects_output_t * output) +{ + if (output->common_prefixes) + { + qs_string_item_t *item = NULL; + qs_string_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_string_item_t, item, output->common_prefixes) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(output->common_prefixes); + } + if (output->delimiter) + { + free(output->delimiter); + } + if (output->keys) + { + qs_key_item_t *item = NULL; + qs_key_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_key_item_t, item, output->keys) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + release_key(item->content); + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(output->keys); + } + if (output->limit) + { + free(output->limit); + } + if (output->marker) + { + free(output->marker); + } + if (output->name) + { + free(output->name); + } + if (output->next_marker) + { + free(output->next_marker); + } + if (output->owner) + { + release_owner(output->owner); + free(output->owner); + } + if (output->prefix) + { + free(output->prefix); + } + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_list_objects(qs_list_objects_input_t * input, + qs_list_objects_output_t * output, + qs_context_handle context_hdl) +{ + //init class ListObjectsinputCpp + ListObjectsInput inputCpp; + ListObjectsOutput outputCpp; + // packer cpp input + if (input->delimiter) + { + inputCpp.SetDelimiter(input->delimiter); + } + if (input->limit) + { + inputCpp.SetLimit(*input->limit); + } + if (input->marker) + { + inputCpp.SetMarker(input->marker); + } + if (input->prefix) + { + inputCpp.SetPrefix(input->prefix); + } + // init output + init_list_objects_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->ListObjects(inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->common_prefixes = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(output->common_prefixes); + std::vector < std::string > commonPrefixes = + outputCpp.GetCommonPrefixes(); + for (std::vector < std::string >::iterator it = commonPrefixes.begin(); + it != commonPrefixes.end(); it++) + { + qs_string_item_t *item = + (qs_string_item_t *) malloc(sizeof(qs_string_item_t)); + int CommonPrefixesLength = it->length(); + if (CommonPrefixesLength > 0) + { + item->content = (char *) malloc(CommonPrefixesLength + 1); + memset(item->content, 0, CommonPrefixesLength + 1); + item->content = (char *) malloc(CommonPrefixesLength + 1); + strncpy(item->content, it->c_str(), CommonPrefixesLength); + } + else + { + item->content = NULL; + } + qs_list_append(&item->node, output->common_prefixes); + } + int DelimiterLength = outputCpp.GetDelimiter().length(); + if (DelimiterLength > 0) + { + output->delimiter = (char *) malloc(DelimiterLength + 1); + memset(output->delimiter, 0, DelimiterLength + 1); + strncpy(output->delimiter, outputCpp.GetDelimiter().c_str(), + DelimiterLength); + } + else + { + output->delimiter = NULL; + } + output->keys = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(output->keys); + std::vector < KeyType > keys = outputCpp.GetKeys(); + for (std::vector < KeyType >::iterator it = keys.begin(); + it != keys.end(); it++) + { + qs_key_item_t *item = + (qs_key_item_t *) malloc(sizeof(qs_key_item_t)); + item->content = it->toCStyleObj(); + qs_list_append(&item->node, output->keys); + } + output->limit = (int *) malloc(sizeof(int)); + *output->limit = outputCpp.GetLimit(); + int MarkerLength = outputCpp.GetMarker().length(); + if (MarkerLength > 0) + { + output->marker = (char *) malloc(MarkerLength + 1); + memset(output->marker, 0, MarkerLength + 1); + strncpy(output->marker, outputCpp.GetMarker().c_str(), + MarkerLength); + } + else + { + output->marker = NULL; + } + int NameLength = outputCpp.GetName().length(); + if (NameLength > 0) + { + output->name = (char *) malloc(NameLength + 1); + memset(output->name, 0, NameLength + 1); + strncpy(output->name, outputCpp.GetName().c_str(), NameLength); + } + else + { + output->name = NULL; + } + int NextMarkerLength = outputCpp.GetNextMarker().length(); + if (NextMarkerLength > 0) + { + output->next_marker = (char *) malloc(NextMarkerLength + 1); + memset(output->next_marker, 0, NextMarkerLength + 1); + strncpy(output->next_marker, outputCpp.GetNextMarker().c_str(), + NextMarkerLength); + } + else + { + output->next_marker = NULL; + } + output->owner = outputCpp.GetOwner().toCStyleObj(); + int PrefixLength = outputCpp.GetPrefix().length(); + if (PrefixLength > 0) + { + output->prefix = (char *) malloc(PrefixLength + 1); + memset(output->prefix, 0, PrefixLength + 1); + strncpy(output->prefix, outputCpp.GetPrefix().c_str(), + PrefixLength); + } + else + { + output->prefix = NULL; + } + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// put_bucketInput init function. +void init_put_bucket_input(qs_put_bucket_input_t * input) +{ + // nothing to do; + return; +} + +// put_bucketoutput init function. +void init_put_bucket_output(qs_put_bucket_output_t * output) +{ + qs_init_error_info(&output->error_info); + return; +} + +// put_bucket Output release function. +void release_put_bucket_output(qs_put_bucket_output_t * output) +{ + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_put_bucket(qs_put_bucket_input_t * input, + qs_put_bucket_output_t * output, + qs_context_handle context_hdl) +{ + //init class PutBucketinputCpp + PutBucketInput inputCpp; + PutBucketOutput outputCpp; + // packer cpp input + // init output + init_put_bucket_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->PutBucket(inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// put_bucket_aclInput init function. +void init_put_bucket_acl_input(qs_put_bucket_acl_input_t * input) +{ + input->acl = NULL; + return; +} + +// put_bucket_acloutput init function. +void init_put_bucket_acl_output(qs_put_bucket_acl_output_t * output) +{ + qs_init_error_info(&output->error_info); + return; +} + +// put_bucket_acl Output release function. +void release_put_bucket_acl_output(qs_put_bucket_acl_output_t * output) +{ + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_put_bucket_acl(qs_put_bucket_acl_input_t * input, + qs_put_bucket_acl_output_t * output, + qs_context_handle context_hdl) +{ + //init class PutBucketACLinputCpp + PutBucketACLInput inputCpp; + PutBucketACLOutput outputCpp; + // packer cpp input + if (input->acl) + { + //qs_list_t list_acl; + //qs_list_init(list_acl); + std::vector < ACLType > ACL; + qs_acl_item_t *item; + qs_list_for_each_entry(qs_acl_item_t, item, input->acl) + { + ACL.push_back(*item->content); + } + inputCpp.SetACL(ACL); + } + // init output + init_put_bucket_acl_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->PutBucketACL(inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// put_bucket_corsInput init function. +void init_put_bucket_cors_input(qs_put_bucket_cors_input_t * input) +{ + input->cors_rules = NULL; + return; +} + +// put_bucket_corsoutput init function. +void init_put_bucket_cors_output(qs_put_bucket_cors_output_t * output) +{ + qs_init_error_info(&output->error_info); + return; +} + +// put_bucket_cors Output release function. +void release_put_bucket_cors_output(qs_put_bucket_cors_output_t * output) +{ + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_put_bucket_cors(qs_put_bucket_cors_input_t * input, + qs_put_bucket_cors_output_t * output, + qs_context_handle context_hdl) +{ + //init class PutBucketCORSinputCpp + PutBucketCORSInput inputCpp; + PutBucketCORSOutput outputCpp; + // packer cpp input + if (input->cors_rules) + { + //qs_list_t list_cors_rules; + //qs_list_init(list_cors_rules); + std::vector < CORSRuleType > CORSRules; + qs_cors_rule_item_t *item; + qs_list_for_each_entry(qs_cors_rule_item_t, item, input->cors_rules) + { + CORSRules.push_back(*item->content); + } + inputCpp.SetCORSRules(CORSRules); + } + // init output + init_put_bucket_cors_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->PutBucketCORS(inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// put_bucket_external_mirrorInput init function. +void init_put_bucket_external_mirror_input(qs_put_bucket_external_mirror_input_t + * input) +{ + input->source_site = NULL; + return; +} + +// put_bucket_external_mirroroutput init function. +void +init_put_bucket_external_mirror_output(qs_put_bucket_external_mirror_output_t * + output) +{ + qs_init_error_info(&output->error_info); + return; +} + +// put_bucket_external_mirror Output release function. +void +release_put_bucket_external_mirror_output(qs_put_bucket_external_mirror_output_t + * output) +{ + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_put_bucket_external_mirror(qs_put_bucket_external_mirror_input_t * + input, + qs_put_bucket_external_mirror_output_t * + output, qs_context_handle context_hdl) +{ + //init class PutBucketExternalMirrorinputCpp + PutBucketExternalMirrorInput inputCpp; + PutBucketExternalMirrorOutput outputCpp; + // packer cpp input + if (input->source_site) + { + inputCpp.SetSourceSite(input->source_site); + } + // init output + init_put_bucket_external_mirror_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->PutBucketExternalMirror(inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// put_bucket_policyInput init function. +void init_put_bucket_policy_input(qs_put_bucket_policy_input_t * input) +{ + input->statement = NULL; + return; +} + +// put_bucket_policyoutput init function. +void init_put_bucket_policy_output(qs_put_bucket_policy_output_t * output) +{ + qs_init_error_info(&output->error_info); + return; +} + +// put_bucket_policy Output release function. +void release_put_bucket_policy_output(qs_put_bucket_policy_output_t * output) +{ + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_put_bucket_policy(qs_put_bucket_policy_input_t * input, + qs_put_bucket_policy_output_t * output, + qs_context_handle context_hdl) +{ + //init class PutBucketPolicyinputCpp + PutBucketPolicyInput inputCpp; + PutBucketPolicyOutput outputCpp; + // packer cpp input + if (input->statement) + { + //qs_list_t list_statement; + //qs_list_init(list_statement); + std::vector < StatementType > Statement; + qs_statement_item_t *item; + qs_list_for_each_entry(qs_statement_item_t, item, input->statement) + { + Statement.push_back(*item->content); + } + inputCpp.SetStatement(Statement); + } + // init output + init_put_bucket_policy_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->PutBucketPolicy(inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// abort_multipart_uploadInput init function. +void init_abort_multipart_upload_input(qs_abort_multipart_upload_input_t * + input) +{ + input->upload_id = NULL; + return; +} + +// abort_multipart_uploadoutput init function. +void init_abort_multipart_upload_output(qs_abort_multipart_upload_output_t * + output) +{ + qs_init_error_info(&output->error_info); + return; +} + +// abort_multipart_upload Output release function. +void release_abort_multipart_upload_output(qs_abort_multipart_upload_output_t * + output) +{ + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_abort_multipart_upload(char *objectKey, + qs_abort_multipart_upload_input_t * input, + qs_abort_multipart_upload_output_t * output, + qs_context_handle context_hdl) +{ + //init class AbortMultipartUploadinputCpp + AbortMultipartUploadInput inputCpp; + AbortMultipartUploadOutput outputCpp; + // packer cpp input + if (input->upload_id) + { + inputCpp.SetUploadID(input->upload_id); + } + // init output + init_abort_multipart_upload_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = + qsBucket->AbortMultipartUpload(objectKey, inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// complete_multipart_uploadInput init function. +void init_complete_multipart_upload_input(qs_complete_multipart_upload_input_t * + input) +{ + input->upload_id = NULL; + input->etag = NULL; + input->x_qs_encryption_customer_algorithm = NULL; + input->x_qs_encryption_customer_key = NULL; + input->x_qs_encryption_customer_key_md5 = NULL; + input->object_parts = NULL; + return; +} + +// complete_multipart_uploadoutput init function. +void init_complete_multipart_upload_output(qs_complete_multipart_upload_output_t + * output) +{ + output->x_qs_encryption_customer_algorithm = NULL; + qs_init_error_info(&output->error_info); + return; +} + +// complete_multipart_upload Output release function. +void +release_complete_multipart_upload_output(qs_complete_multipart_upload_output_t * + output) +{ + if (output->x_qs_encryption_customer_algorithm) + { + free(output->x_qs_encryption_customer_algorithm); + } + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_complete_multipart_upload(char *objectKey, + qs_complete_multipart_upload_input_t * + input, + qs_complete_multipart_upload_output_t * + output, qs_context_handle context_hdl) +{ + //init class CompleteMultipartUploadinputCpp + CompleteMultipartUploadInput inputCpp; + CompleteMultipartUploadOutput outputCpp; + // packer cpp input + if (input->upload_id) + { + inputCpp.SetUploadID(input->upload_id); + } + if (input->etag) + { + inputCpp.SetETag(input->etag); + } + if (input->x_qs_encryption_customer_algorithm) + { + inputCpp.SetXQSEncryptionCustomerAlgorithm(input-> + x_qs_encryption_customer_algorithm); + } + if (input->x_qs_encryption_customer_key) + { + inputCpp.SetXQSEncryptionCustomerKey(input-> + x_qs_encryption_customer_key); + } + if (input->x_qs_encryption_customer_key_md5) + { + inputCpp.SetXQSEncryptionCustomerKeyMD5(input-> + x_qs_encryption_customer_key_md5); + } + if (input->object_parts) + { + //qs_list_t list_object_parts; + //qs_list_init(list_object_parts); + std::vector < ObjectPartType > ObjectParts; + qs_object_part_item_t *item; + qs_list_for_each_entry(qs_object_part_item_t, item, input->object_parts) + { + ObjectParts.push_back(*item->content); + } + inputCpp.SetObjectParts(ObjectParts); + } + // init output + init_complete_multipart_upload_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = + qsBucket->CompleteMultipartUpload(objectKey, inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + int XQSEncryptionCustomerAlgorithmLength = + outputCpp.GetXQSEncryptionCustomerAlgorithm().length(); + if (XQSEncryptionCustomerAlgorithmLength > 0) + { + output->x_qs_encryption_customer_algorithm = + (char *) malloc(XQSEncryptionCustomerAlgorithmLength + 1); + memset(output->x_qs_encryption_customer_algorithm, 0, + XQSEncryptionCustomerAlgorithmLength + 1); + strncpy(output->x_qs_encryption_customer_algorithm, + outputCpp.GetXQSEncryptionCustomerAlgorithm().c_str(), + XQSEncryptionCustomerAlgorithmLength); + } + else + { + output->x_qs_encryption_customer_algorithm = NULL; + } + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// delete_objectInput init function. +void init_delete_object_input(qs_delete_object_input_t * input) +{ + // nothing to do; + return; +} + +// delete_objectoutput init function. +void init_delete_object_output(qs_delete_object_output_t * output) +{ + qs_init_error_info(&output->error_info); + return; +} + +// delete_object Output release function. +void release_delete_object_output(qs_delete_object_output_t * output) +{ + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_delete_object(char *objectKey, qs_delete_object_input_t * input, + qs_delete_object_output_t * output, + qs_context_handle context_hdl) +{ + //init class DeleteObjectinputCpp + DeleteObjectInput inputCpp; + DeleteObjectOutput outputCpp; + // packer cpp input + // init output + init_delete_object_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->DeleteObject(objectKey, inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// get_objectInput init function. +void init_get_object_input(qs_get_object_input_t * input) +{ + input->response_cache_control = NULL; + input->response_content_disposition = NULL; + input->response_content_encoding = NULL; + input->response_content_language = NULL; + input->response_content_type = NULL; + input->response_expires = NULL; + input->if_match = NULL; + input->if_modified_since = NULL; + input->if_none_match = NULL; + input->if_unmodified_since = NULL; + input->range = NULL; + input->x_qs_encryption_customer_algorithm = NULL; + input->x_qs_encryption_customer_key = NULL; + input->x_qs_encryption_customer_key_md5 = NULL; + return; +} + +// get_objectoutput init function. +void init_get_object_output(qs_get_object_output_t * output) +{ + output->cache_control = NULL; + output->content_disposition = NULL; + output->content_encoding = NULL; + output->content_language = NULL; + output->content_length = NULL; + output->content_range = NULL; + output->content_type = NULL; + output->etag = NULL; + output->expires = NULL; + output->last_modified = NULL; + output->x_qs_encryption_customer_algorithm = NULL; + output->bufLength = NULL; + output->bodybuf = NULL; + qs_init_error_info(&output->error_info); + qs_init_error_info(&output->error_info); + qs_init_error_info(&output->error_info); + qs_init_error_info(&output->error_info); + return; +} + +// get_object Output release function. +void release_get_object_output(qs_get_object_output_t * output) +{ + if (output->cache_control) + { + free(output->cache_control); + } + if (output->content_disposition) + { + free(output->content_disposition); + } + if (output->content_encoding) + { + free(output->content_encoding); + } + if (output->content_language) + { + free(output->content_language); + } + if (output->content_length) + { + free(output->content_length); + } + if (output->content_range) + { + free(output->content_range); + } + if (output->content_type) + { + free(output->content_type); + } + if (output->etag) + { + free(output->etag); + } + if (output->expires) + { + free(output->expires); + } + if (output->last_modified) + { + free(output->last_modified); + } + if (output->x_qs_encryption_customer_algorithm) + { + free(output->x_qs_encryption_customer_algorithm); + } + // release binary body content + if (output->bodybuf) + { + free(output->bodybuf); + } + if (output->bufLength) + { + free(output->bufLength); + } + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_get_object(char *objectKey, qs_get_object_input_t * input, + qs_get_object_output_t * output, + qs_context_handle context_hdl) +{ + //init class GetObjectinputCpp + GetObjectInput inputCpp; + GetObjectOutput outputCpp; + // packer cpp input + if (input->response_cache_control) + { + inputCpp.SetResponseCacheControl(input->response_cache_control); + } + if (input->response_content_disposition) + { + inputCpp.SetResponseContentDisposition(input-> + response_content_disposition); + } + if (input->response_content_encoding) + { + inputCpp.SetResponseContentEncoding(input->response_content_encoding); + } + if (input->response_content_language) + { + inputCpp.SetResponseContentLanguage(input->response_content_language); + } + if (input->response_content_type) + { + inputCpp.SetResponseContentType(input->response_content_type); + } + if (input->response_expires) + { + inputCpp.SetResponseExpires(input->response_expires); + } + if (input->if_match) + { + inputCpp.SetIfMatch(input->if_match); + } + if (input->if_modified_since) + { + inputCpp.SetIfModifiedSince(input->if_modified_since); + } + if (input->if_none_match) + { + inputCpp.SetIfNoneMatch(input->if_none_match); + } + if (input->if_unmodified_since) + { + inputCpp.SetIfUnmodifiedSince(input->if_unmodified_since); + } + if (input->range) + { + inputCpp.SetRange(input->range); + } + if (input->x_qs_encryption_customer_algorithm) + { + inputCpp.SetXQSEncryptionCustomerAlgorithm(input-> + x_qs_encryption_customer_algorithm); + } + if (input->x_qs_encryption_customer_key) + { + inputCpp.SetXQSEncryptionCustomerKey(input-> + x_qs_encryption_customer_key); + } + if (input->x_qs_encryption_customer_key_md5) + { + inputCpp.SetXQSEncryptionCustomerKeyMD5(input-> + x_qs_encryption_customer_key_md5); + } + // init output + init_get_object_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->GetObject(objectKey, inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + int CacheControlLength = outputCpp.GetCacheControl().length(); + if (CacheControlLength > 0) + { + output->cache_control = (char *) malloc(CacheControlLength + 1); + memset(output->cache_control, 0, CacheControlLength + 1); + strncpy(output->cache_control, outputCpp.GetCacheControl().c_str(), + CacheControlLength); + } + else + { + output->cache_control = NULL; + } + int ContentDispositionLength = + outputCpp.GetContentDisposition().length(); + if (ContentDispositionLength > 0) + { + output->content_disposition = + (char *) malloc(ContentDispositionLength + 1); + memset(output->content_disposition, 0, + ContentDispositionLength + 1); + strncpy(output->content_disposition, + outputCpp.GetContentDisposition().c_str(), + ContentDispositionLength); + } + else + { + output->content_disposition = NULL; + } + int ContentEncodingLength = outputCpp.GetContentEncoding().length(); + if (ContentEncodingLength > 0) + { + output->content_encoding = + (char *) malloc(ContentEncodingLength + 1); + memset(output->content_encoding, 0, ContentEncodingLength + 1); + strncpy(output->content_encoding, + outputCpp.GetContentEncoding().c_str(), + ContentEncodingLength); + } + else + { + output->content_encoding = NULL; + } + int ContentLanguageLength = outputCpp.GetContentLanguage().length(); + if (ContentLanguageLength > 0) + { + output->content_language = + (char *) malloc(ContentLanguageLength + 1); + memset(output->content_language, 0, ContentLanguageLength + 1); + strncpy(output->content_language, + outputCpp.GetContentLanguage().c_str(), + ContentLanguageLength); + } + else + { + output->content_language = NULL; + } + output->content_length = (long *) malloc(sizeof(long)); + *output->content_length = outputCpp.GetContentLength(); + int ContentRangeLength = outputCpp.GetContentRange().length(); + if (ContentRangeLength > 0) + { + output->content_range = (char *) malloc(ContentRangeLength + 1); + memset(output->content_range, 0, ContentRangeLength + 1); + strncpy(output->content_range, outputCpp.GetContentRange().c_str(), + ContentRangeLength); + } + else + { + output->content_range = NULL; + } + int ContentTypeLength = outputCpp.GetContentType().length(); + if (ContentTypeLength > 0) + { + output->content_type = (char *) malloc(ContentTypeLength + 1); + memset(output->content_type, 0, ContentTypeLength + 1); + strncpy(output->content_type, outputCpp.GetContentType().c_str(), + ContentTypeLength); + } + else + { + output->content_type = NULL; + } + int ETagLength = outputCpp.GetETag().length(); + if (ETagLength > 0) + { + output->etag = (char *) malloc(ETagLength + 1); + memset(output->etag, 0, ETagLength + 1); + strncpy(output->etag, outputCpp.GetETag().c_str(), ETagLength); + } + else + { + output->etag = NULL; + } + int ExpiresLength = outputCpp.GetExpires().length(); + if (ExpiresLength > 0) + { + output->expires = (char *) malloc(ExpiresLength + 1); + memset(output->expires, 0, ExpiresLength + 1); + strncpy(output->expires, outputCpp.GetExpires().c_str(), + ExpiresLength); + } + else + { + output->expires = NULL; + } + int LastModifiedLength = outputCpp.GetLastModified().length(); + if (LastModifiedLength > 0) + { + output->last_modified = (char *) malloc(LastModifiedLength + 1); + memset(output->last_modified, 0, LastModifiedLength + 1); + strncpy(output->last_modified, outputCpp.GetLastModified().c_str(), + LastModifiedLength); + } + else + { + output->last_modified = NULL; + } + int XQSEncryptionCustomerAlgorithmLength = + outputCpp.GetXQSEncryptionCustomerAlgorithm().length(); + if (XQSEncryptionCustomerAlgorithmLength > 0) + { + output->x_qs_encryption_customer_algorithm = + (char *) malloc(XQSEncryptionCustomerAlgorithmLength + 1); + memset(output->x_qs_encryption_customer_algorithm, 0, + XQSEncryptionCustomerAlgorithmLength + 1); + strncpy(output->x_qs_encryption_customer_algorithm, + outputCpp.GetXQSEncryptionCustomerAlgorithm().c_str(), + XQSEncryptionCustomerAlgorithmLength); + } + else + { + output->x_qs_encryption_customer_algorithm = NULL; + } + std::iostream * respStreamBody = outputCpp.GetBody(); + if (respStreamBody) + { + respStreamBody->seekg(0, outputCpp.GetBody()->end); + size_t streamSize = outputCpp.GetBody()->tellg(); + respStreamBody->seekg(0, outputCpp.GetBody()->beg); + output->bodybuf = (void *) malloc(streamSize); + output->bufLength = (int64_t *) malloc(sizeof(int64_t)); + //size_t readCount = (streamSize > *output->bufLength)? *output->bufLength : streamSize; + respStreamBody->read((char *) output->bodybuf, streamSize); + *output->bufLength = + static_cast < int64_t > (respStreamBody->gcount());; + //clean up + delete respStreamBody; + } + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// head_objectInput init function. +void init_head_object_input(qs_head_object_input_t * input) +{ + input->if_match = NULL; + input->if_modified_since = NULL; + input->if_none_match = NULL; + input->if_unmodified_since = NULL; + input->x_qs_encryption_customer_algorithm = NULL; + input->x_qs_encryption_customer_key = NULL; + input->x_qs_encryption_customer_key_md5 = NULL; + return; +} + +// head_objectoutput init function. +void init_head_object_output(qs_head_object_output_t * output) +{ + output->content_length = NULL; + output->content_type = NULL; + output->etag = NULL; + output->last_modified = NULL; + output->x_qs_encryption_customer_algorithm = NULL; + qs_init_error_info(&output->error_info); + return; +} + +// head_object Output release function. +void release_head_object_output(qs_head_object_output_t * output) +{ + if (output->content_length) + { + free(output->content_length); + } + if (output->content_type) + { + free(output->content_type); + } + if (output->etag) + { + free(output->etag); + } + if (output->last_modified) + { + free(output->last_modified); + } + if (output->x_qs_encryption_customer_algorithm) + { + free(output->x_qs_encryption_customer_algorithm); + } + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_head_object(char *objectKey, qs_head_object_input_t * input, + qs_head_object_output_t * output, + qs_context_handle context_hdl) +{ + //init class HeadObjectinputCpp + HeadObjectInput inputCpp; + HeadObjectOutput outputCpp; + // packer cpp input + if (input->if_match) + { + inputCpp.SetIfMatch(input->if_match); + } + if (input->if_modified_since) + { + inputCpp.SetIfModifiedSince(input->if_modified_since); + } + if (input->if_none_match) + { + inputCpp.SetIfNoneMatch(input->if_none_match); + } + if (input->if_unmodified_since) + { + inputCpp.SetIfUnmodifiedSince(input->if_unmodified_since); + } + if (input->x_qs_encryption_customer_algorithm) + { + inputCpp.SetXQSEncryptionCustomerAlgorithm(input-> + x_qs_encryption_customer_algorithm); + } + if (input->x_qs_encryption_customer_key) + { + inputCpp.SetXQSEncryptionCustomerKey(input-> + x_qs_encryption_customer_key); + } + if (input->x_qs_encryption_customer_key_md5) + { + inputCpp.SetXQSEncryptionCustomerKeyMD5(input-> + x_qs_encryption_customer_key_md5); + } + // init output + init_head_object_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->HeadObject(objectKey, inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->content_length = (long *) malloc(sizeof(long)); + *output->content_length = outputCpp.GetContentLength(); + int ContentTypeLength = outputCpp.GetContentType().length(); + if (ContentTypeLength > 0) + { + output->content_type = (char *) malloc(ContentTypeLength + 1); + memset(output->content_type, 0, ContentTypeLength + 1); + strncpy(output->content_type, outputCpp.GetContentType().c_str(), + ContentTypeLength); + } + else + { + output->content_type = NULL; + } + int ETagLength = outputCpp.GetETag().length(); + if (ETagLength > 0) + { + output->etag = (char *) malloc(ETagLength + 1); + memset(output->etag, 0, ETagLength + 1); + strncpy(output->etag, outputCpp.GetETag().c_str(), ETagLength); + } + else + { + output->etag = NULL; + } + int LastModifiedLength = outputCpp.GetLastModified().length(); + if (LastModifiedLength > 0) + { + output->last_modified = (char *) malloc(LastModifiedLength + 1); + memset(output->last_modified, 0, LastModifiedLength + 1); + strncpy(output->last_modified, outputCpp.GetLastModified().c_str(), + LastModifiedLength); + } + else + { + output->last_modified = NULL; + } + int XQSEncryptionCustomerAlgorithmLength = + outputCpp.GetXQSEncryptionCustomerAlgorithm().length(); + if (XQSEncryptionCustomerAlgorithmLength > 0) + { + output->x_qs_encryption_customer_algorithm = + (char *) malloc(XQSEncryptionCustomerAlgorithmLength + 1); + memset(output->x_qs_encryption_customer_algorithm, 0, + XQSEncryptionCustomerAlgorithmLength + 1); + strncpy(output->x_qs_encryption_customer_algorithm, + outputCpp.GetXQSEncryptionCustomerAlgorithm().c_str(), + XQSEncryptionCustomerAlgorithmLength); + } + else + { + output->x_qs_encryption_customer_algorithm = NULL; + } + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// image_processInput init function. +void init_image_process_input(qs_image_process_input_t * input) +{ + input->action = NULL; + input->response_cache_control = NULL; + input->response_content_disposition = NULL; + input->response_content_encoding = NULL; + input->response_content_language = NULL; + input->response_content_type = NULL; + input->response_expires = NULL; + input->if_modified_since = NULL; + return; +} + +// image_processoutput init function. +void init_image_process_output(qs_image_process_output_t * output) +{ + output->content_length = NULL; + output->bufLength = NULL; + output->bodybuf = NULL; + qs_init_error_info(&output->error_info); + qs_init_error_info(&output->error_info); + return; +} + +// image_process Output release function. +void release_image_process_output(qs_image_process_output_t * output) +{ + if (output->content_length) + { + free(output->content_length); + } + // release binary body content + if (output->bodybuf) + { + free(output->bodybuf); + } + if (output->bufLength) + { + free(output->bufLength); + } + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_image_process(char *objectKey, qs_image_process_input_t * input, + qs_image_process_output_t * output, + qs_context_handle context_hdl) +{ + //init class ImageProcessinputCpp + ImageProcessInput inputCpp; + ImageProcessOutput outputCpp; + // packer cpp input + if (input->action) + { + inputCpp.SetAction(input->action); + } + if (input->response_cache_control) + { + inputCpp.SetResponseCacheControl(input->response_cache_control); + } + if (input->response_content_disposition) + { + inputCpp.SetResponseContentDisposition(input-> + response_content_disposition); + } + if (input->response_content_encoding) + { + inputCpp.SetResponseContentEncoding(input->response_content_encoding); + } + if (input->response_content_language) + { + inputCpp.SetResponseContentLanguage(input->response_content_language); + } + if (input->response_content_type) + { + inputCpp.SetResponseContentType(input->response_content_type); + } + if (input->response_expires) + { + inputCpp.SetResponseExpires(input->response_expires); + } + if (input->if_modified_since) + { + inputCpp.SetIfModifiedSince(input->if_modified_since); + } + // init output + init_image_process_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->ImageProcess(objectKey, inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->content_length = (long *) malloc(sizeof(long)); + *output->content_length = outputCpp.GetContentLength(); + std::iostream * respStreamBody = outputCpp.GetBody(); + if (respStreamBody) + { + respStreamBody->seekg(0, outputCpp.GetBody()->end); + size_t streamSize = outputCpp.GetBody()->tellg(); + respStreamBody->seekg(0, outputCpp.GetBody()->beg); + output->bodybuf = (void *) malloc(streamSize); + output->bufLength = (int64_t *) malloc(sizeof(int64_t)); + //size_t readCount = (streamSize > *output->bufLength)? *output->bufLength : streamSize; + respStreamBody->read((char *) output->bodybuf, streamSize); + *output->bufLength = + static_cast < int64_t > (respStreamBody->gcount());; + //clean up + delete respStreamBody; + } + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// initiate_multipart_uploadInput init function. +void init_initiate_multipart_upload_input(qs_initiate_multipart_upload_input_t * + input) +{ + input->content_type = NULL; + input->x_qs_encryption_customer_algorithm = NULL; + input->x_qs_encryption_customer_key = NULL; + input->x_qs_encryption_customer_key_md5 = NULL; + return; +} + +// initiate_multipart_uploadoutput init function. +void init_initiate_multipart_upload_output(qs_initiate_multipart_upload_output_t + * output) +{ + output->x_qs_encryption_customer_algorithm = NULL; + output->bucket = NULL; + output->key = NULL; + output->upload_id = NULL; + qs_init_error_info(&output->error_info); + return; +} + +// initiate_multipart_upload Output release function. +void +release_initiate_multipart_upload_output(qs_initiate_multipart_upload_output_t * + output) +{ + if (output->x_qs_encryption_customer_algorithm) + { + free(output->x_qs_encryption_customer_algorithm); + } + if (output->bucket) + { + free(output->bucket); + } + if (output->key) + { + free(output->key); + } + if (output->upload_id) + { + free(output->upload_id); + } + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_initiate_multipart_upload(char *objectKey, + qs_initiate_multipart_upload_input_t * + input, + qs_initiate_multipart_upload_output_t * + output, qs_context_handle context_hdl) +{ + //init class InitiateMultipartUploadinputCpp + InitiateMultipartUploadInput inputCpp; + InitiateMultipartUploadOutput outputCpp; + // packer cpp input + if (input->content_type) + { + inputCpp.SetContentType(input->content_type); + } + if (input->x_qs_encryption_customer_algorithm) + { + inputCpp.SetXQSEncryptionCustomerAlgorithm(input-> + x_qs_encryption_customer_algorithm); + } + if (input->x_qs_encryption_customer_key) + { + inputCpp.SetXQSEncryptionCustomerKey(input-> + x_qs_encryption_customer_key); + } + if (input->x_qs_encryption_customer_key_md5) + { + inputCpp.SetXQSEncryptionCustomerKeyMD5(input-> + x_qs_encryption_customer_key_md5); + } + // init output + init_initiate_multipart_upload_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = + qsBucket->InitiateMultipartUpload(objectKey, inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + int XQSEncryptionCustomerAlgorithmLength = + outputCpp.GetXQSEncryptionCustomerAlgorithm().length(); + if (XQSEncryptionCustomerAlgorithmLength > 0) + { + output->x_qs_encryption_customer_algorithm = + (char *) malloc(XQSEncryptionCustomerAlgorithmLength + 1); + memset(output->x_qs_encryption_customer_algorithm, 0, + XQSEncryptionCustomerAlgorithmLength + 1); + strncpy(output->x_qs_encryption_customer_algorithm, + outputCpp.GetXQSEncryptionCustomerAlgorithm().c_str(), + XQSEncryptionCustomerAlgorithmLength); + } + else + { + output->x_qs_encryption_customer_algorithm = NULL; + } + int BucketLength = outputCpp.GetBucket().length(); + if (BucketLength > 0) + { + output->bucket = (char *) malloc(BucketLength + 1); + memset(output->bucket, 0, BucketLength + 1); + strncpy(output->bucket, outputCpp.GetBucket().c_str(), + BucketLength); + } + else + { + output->bucket = NULL; + } + int KeyLength = outputCpp.GetKey().length(); + if (KeyLength > 0) + { + output->key = (char *) malloc(KeyLength + 1); + memset(output->key, 0, KeyLength + 1); + strncpy(output->key, outputCpp.GetKey().c_str(), KeyLength); + } + else + { + output->key = NULL; + } + int UploadIDLength = outputCpp.GetUploadID().length(); + if (UploadIDLength > 0) + { + output->upload_id = (char *) malloc(UploadIDLength + 1); + memset(output->upload_id, 0, UploadIDLength + 1); + strncpy(output->upload_id, outputCpp.GetUploadID().c_str(), + UploadIDLength); + } + else + { + output->upload_id = NULL; + } + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// list_multipartInput init function. +void init_list_multipart_input(qs_list_multipart_input_t * input) +{ + input->limit = NULL; + input->part_number_marker = NULL; + input->upload_id = NULL; + return; +} + +// list_multipartoutput init function. +void init_list_multipart_output(qs_list_multipart_output_t * output) +{ + output->count = NULL; + output->object_parts = NULL; + qs_init_error_info(&output->error_info); + return; +} + +// list_multipart Output release function. +void release_list_multipart_output(qs_list_multipart_output_t * output) +{ + if (output->count) + { + free(output->count); + } + if (output->object_parts) + { + qs_object_part_item_t *item = NULL; + qs_object_part_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_object_part_item_t, item, + output->object_parts) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + release_object_part(item->content); + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(output->object_parts); + } + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_list_multipart(char *objectKey, qs_list_multipart_input_t * input, + qs_list_multipart_output_t * output, + qs_context_handle context_hdl) +{ + //init class ListMultipartinputCpp + ListMultipartInput inputCpp; + ListMultipartOutput outputCpp; + // packer cpp input + if (input->limit) + { + inputCpp.SetLimit(*input->limit); + } + if (input->part_number_marker) + { + inputCpp.SetPartNumberMarker(*input->part_number_marker); + } + if (input->upload_id) + { + inputCpp.SetUploadID(input->upload_id); + } + // init output + init_list_multipart_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->ListMultipart(objectKey, inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + output->count = (int *) malloc(sizeof(int)); + *output->count = outputCpp.GetCount(); + output->object_parts = (qs_list_t *) malloc(sizeof(qs_list_t)); + qs_list_init(output->object_parts); + std::vector < ObjectPartType > objectParts = outputCpp.GetObjectParts(); + for (std::vector < ObjectPartType >::iterator it = objectParts.begin(); + it != objectParts.end(); it++) + { + qs_object_part_item_t *item = + (qs_object_part_item_t *) malloc(sizeof(qs_object_part_item_t)); + item->content = it->toCStyleObj(); + qs_list_append(&item->node, output->object_parts); + } + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// options_objectInput init function. +void init_options_object_input(qs_options_object_input_t * input) +{ + input->access_control_request_headers = NULL; + input->access_control_request_method = NULL; + input->origin = NULL; + return; +} + +// options_objectoutput init function. +void init_options_object_output(qs_options_object_output_t * output) +{ + output->access_control_allow_headers = NULL; + output->access_control_allow_methods = NULL; + output->access_control_allow_origin = NULL; + output->access_control_expose_headers = NULL; + output->access_control_max_age = NULL; + qs_init_error_info(&output->error_info); + return; +} + +// options_object Output release function. +void release_options_object_output(qs_options_object_output_t * output) +{ + if (output->access_control_allow_headers) + { + free(output->access_control_allow_headers); + } + if (output->access_control_allow_methods) + { + free(output->access_control_allow_methods); + } + if (output->access_control_allow_origin) + { + free(output->access_control_allow_origin); + } + if (output->access_control_expose_headers) + { + free(output->access_control_expose_headers); + } + if (output->access_control_max_age) + { + free(output->access_control_max_age); + } + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_options_object(char *objectKey, qs_options_object_input_t * input, + qs_options_object_output_t * output, + qs_context_handle context_hdl) +{ + //init class OptionsObjectinputCpp + OptionsObjectInput inputCpp; + OptionsObjectOutput outputCpp; + // packer cpp input + if (input->access_control_request_headers) + { + inputCpp.SetAccessControlRequestHeaders(input-> + access_control_request_headers); + } + if (input->access_control_request_method) + { + inputCpp.SetAccessControlRequestMethod(input-> + access_control_request_method); + } + if (input->origin) + { + inputCpp.SetOrigin(input->origin); + } + // init output + init_options_object_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->OptionsObject(objectKey, inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + int AccessControlAllowHeadersLength = + outputCpp.GetAccessControlAllowHeaders().length(); + if (AccessControlAllowHeadersLength > 0) + { + output->access_control_allow_headers = + (char *) malloc(AccessControlAllowHeadersLength + 1); + memset(output->access_control_allow_headers, 0, + AccessControlAllowHeadersLength + 1); + strncpy(output->access_control_allow_headers, + outputCpp.GetAccessControlAllowHeaders().c_str(), + AccessControlAllowHeadersLength); + } + else + { + output->access_control_allow_headers = NULL; + } + int AccessControlAllowMethodsLength = + outputCpp.GetAccessControlAllowMethods().length(); + if (AccessControlAllowMethodsLength > 0) + { + output->access_control_allow_methods = + (char *) malloc(AccessControlAllowMethodsLength + 1); + memset(output->access_control_allow_methods, 0, + AccessControlAllowMethodsLength + 1); + strncpy(output->access_control_allow_methods, + outputCpp.GetAccessControlAllowMethods().c_str(), + AccessControlAllowMethodsLength); + } + else + { + output->access_control_allow_methods = NULL; + } + int AccessControlAllowOriginLength = + outputCpp.GetAccessControlAllowOrigin().length(); + if (AccessControlAllowOriginLength > 0) + { + output->access_control_allow_origin = + (char *) malloc(AccessControlAllowOriginLength + 1); + memset(output->access_control_allow_origin, 0, + AccessControlAllowOriginLength + 1); + strncpy(output->access_control_allow_origin, + outputCpp.GetAccessControlAllowOrigin().c_str(), + AccessControlAllowOriginLength); + } + else + { + output->access_control_allow_origin = NULL; + } + int AccessControlExposeHeadersLength = + outputCpp.GetAccessControlExposeHeaders().length(); + if (AccessControlExposeHeadersLength > 0) + { + output->access_control_expose_headers = + (char *) malloc(AccessControlExposeHeadersLength + 1); + memset(output->access_control_expose_headers, 0, + AccessControlExposeHeadersLength + 1); + strncpy(output->access_control_expose_headers, + outputCpp.GetAccessControlExposeHeaders().c_str(), + AccessControlExposeHeadersLength); + } + else + { + output->access_control_expose_headers = NULL; + } + int AccessControlMaxAgeLength = + outputCpp.GetAccessControlMaxAge().length(); + if (AccessControlMaxAgeLength > 0) + { + output->access_control_max_age = + (char *) malloc(AccessControlMaxAgeLength + 1); + memset(output->access_control_max_age, 0, + AccessControlMaxAgeLength + 1); + strncpy(output->access_control_max_age, + outputCpp.GetAccessControlMaxAge().c_str(), + AccessControlMaxAgeLength); + } + else + { + output->access_control_max_age = NULL; + } + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + return err; +} + +// put_objectInput init function. +void init_put_object_input(qs_put_object_input_t * input) +{ + input->content_length = NULL; + input->content_md5 = NULL; + input->content_type = NULL; + input->expect = NULL; + input->x_qs_copy_source = NULL; + input->x_qs_copy_source_encryption_customer_algorithm = NULL; + input->x_qs_copy_source_encryption_customer_key = NULL; + input->x_qs_copy_source_encryption_customer_key_md5 = NULL; + input->x_qs_copy_source_if_match = NULL; + input->x_qs_copy_source_if_modified_since = NULL; + input->x_qs_copy_source_if_none_match = NULL; + input->x_qs_copy_source_if_unmodified_since = NULL; + input->x_qs_encryption_customer_algorithm = NULL; + input->x_qs_encryption_customer_key = NULL; + input->x_qs_encryption_customer_key_md5 = NULL; + input->x_qs_fetch_if_unmodified_since = NULL; + input->x_qs_fetch_source = NULL; + input->x_qs_move_source = NULL; + input->bufLength = NULL; + input->bodybuf = NULL; + return; +} + +// put_objectoutput init function. +void init_put_object_output(qs_put_object_output_t * output) +{ + output->etag = NULL; + output->x_qs_encryption_customer_algorithm = NULL; + qs_init_error_info(&output->error_info); + return; +} + +// put_object Output release function. +void release_put_object_output(qs_put_object_output_t * output) +{ + if (output->etag) + { + free(output->etag); + } + if (output->x_qs_encryption_customer_algorithm) + { + free(output->x_qs_encryption_customer_algorithm); + } + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_put_object(char *objectKey, qs_put_object_input_t * input, + qs_put_object_output_t * output, + qs_context_handle context_hdl) +{ + //init class PutObjectinputCpp + PutObjectInput inputCpp; + PutObjectOutput outputCpp; + std::iostream * reqStreamBody = NULL; + // packer cpp input + if (input->content_length) + { + inputCpp.SetContentLength(*input->content_length); + } + if (input->content_md5) + { + inputCpp.SetContentMD5(input->content_md5); + } + if (input->content_type) + { + inputCpp.SetContentType(input->content_type); + } + if (input->expect) + { + inputCpp.SetExpect(input->expect); + } + if (input->x_qs_copy_source) + { + inputCpp.SetXQSCopySource(input->x_qs_copy_source); + } + if (input->x_qs_copy_source_encryption_customer_algorithm) + { + inputCpp.SetXQSCopySourceEncryptionCustomerAlgorithm(input-> + x_qs_copy_source_encryption_customer_algorithm); + } + if (input->x_qs_copy_source_encryption_customer_key) + { + inputCpp.SetXQSCopySourceEncryptionCustomerKey(input-> + x_qs_copy_source_encryption_customer_key); + } + if (input->x_qs_copy_source_encryption_customer_key_md5) + { + inputCpp.SetXQSCopySourceEncryptionCustomerKeyMD5(input-> + x_qs_copy_source_encryption_customer_key_md5); + } + if (input->x_qs_copy_source_if_match) + { + inputCpp.SetXQSCopySourceIfMatch(input->x_qs_copy_source_if_match); + } + if (input->x_qs_copy_source_if_modified_since) + { + inputCpp.SetXQSCopySourceIfModifiedSince(input-> + x_qs_copy_source_if_modified_since); + } + if (input->x_qs_copy_source_if_none_match) + { + inputCpp.SetXQSCopySourceIfNoneMatch(input-> + x_qs_copy_source_if_none_match); + } + if (input->x_qs_copy_source_if_unmodified_since) + { + inputCpp.SetXQSCopySourceIfUnmodifiedSince(input-> + x_qs_copy_source_if_unmodified_since); + } + if (input->x_qs_encryption_customer_algorithm) + { + inputCpp.SetXQSEncryptionCustomerAlgorithm(input-> + x_qs_encryption_customer_algorithm); + } + if (input->x_qs_encryption_customer_key) + { + inputCpp.SetXQSEncryptionCustomerKey(input-> + x_qs_encryption_customer_key); + } + if (input->x_qs_encryption_customer_key_md5) + { + inputCpp.SetXQSEncryptionCustomerKeyMD5(input-> + x_qs_encryption_customer_key_md5); + } + if (input->x_qs_fetch_if_unmodified_since) + { + inputCpp.SetXQSFetchIfUnmodifiedSince(input-> + x_qs_fetch_if_unmodified_since); + } + if (input->x_qs_fetch_source) + { + inputCpp.SetXQSFetchSource(input->x_qs_fetch_source); + } + if (input->x_qs_move_source) + { + inputCpp.SetXQSMoveSource(input->x_qs_move_source); + } + if (input->bodybuf) + { + reqStreamBody = new QsStream(); + reqStreamBody->write(static_cast < char *>(input->bodybuf), + (size_t) * input->bufLength); + inputCpp.SetBody(reqStreamBody); + } + // init output + init_put_object_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->PutObject(objectKey, inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + int ETagLength = outputCpp.GetETag().length(); + if (ETagLength > 0) + { + output->etag = (char *) malloc(ETagLength + 1); + memset(output->etag, 0, ETagLength + 1); + strncpy(output->etag, outputCpp.GetETag().c_str(), ETagLength); + } + else + { + output->etag = NULL; + } + int XQSEncryptionCustomerAlgorithmLength = + outputCpp.GetXQSEncryptionCustomerAlgorithm().length(); + if (XQSEncryptionCustomerAlgorithmLength > 0) + { + output->x_qs_encryption_customer_algorithm = + (char *) malloc(XQSEncryptionCustomerAlgorithmLength + 1); + memset(output->x_qs_encryption_customer_algorithm, 0, + XQSEncryptionCustomerAlgorithmLength + 1); + strncpy(output->x_qs_encryption_customer_algorithm, + outputCpp.GetXQSEncryptionCustomerAlgorithm().c_str(), + XQSEncryptionCustomerAlgorithmLength); + } + else + { + output->x_qs_encryption_customer_algorithm = NULL; + } + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + // clean up + if (reqStreamBody) + { + delete reqStreamBody; + reqStreamBody = NULL; + } + return err; +} + +// upload_multipartInput init function. +void init_upload_multipart_input(qs_upload_multipart_input_t * input) +{ + input->part_number = NULL; + input->upload_id = NULL; + input->content_length = NULL; + input->content_md5 = NULL; + input->x_qs_copy_range = NULL; + input->x_qs_copy_source = NULL; + input->x_qs_copy_source_encryption_customer_algorithm = NULL; + input->x_qs_copy_source_encryption_customer_key = NULL; + input->x_qs_copy_source_encryption_customer_key_md5 = NULL; + input->x_qs_copy_source_if_match = NULL; + input->x_qs_copy_source_if_modified_since = NULL; + input->x_qs_copy_source_if_none_match = NULL; + input->x_qs_copy_source_if_unmodified_since = NULL; + input->x_qs_encryption_customer_algorithm = NULL; + input->x_qs_encryption_customer_key = NULL; + input->x_qs_encryption_customer_key_md5 = NULL; + input->bufLength = NULL; + input->bodybuf = NULL; + return; +} + +// upload_multipartoutput init function. +void init_upload_multipart_output(qs_upload_multipart_output_t * output) +{ + output->etag = NULL; + output->x_qs_content_copy_range = NULL; + output->x_qs_encryption_customer_algorithm = NULL; + qs_init_error_info(&output->error_info); + return; +} + +// upload_multipart Output release function. +void release_upload_multipart_output(qs_upload_multipart_output_t * output) +{ + if (output->etag) + { + free(output->etag); + } + if (output->x_qs_content_copy_range) + { + free(output->x_qs_content_copy_range); + } + if (output->x_qs_encryption_customer_algorithm) + { + free(output->x_qs_encryption_customer_algorithm); + } + qs_release_error_info(&output->error_info); + return; +} + +QsError qs_upload_multipart(char *objectKey, + qs_upload_multipart_input_t * input, + qs_upload_multipart_output_t * output, + qs_context_handle context_hdl) +{ + //init class UploadMultipartinputCpp + UploadMultipartInput inputCpp; + UploadMultipartOutput outputCpp; + std::iostream * reqStreamBody = NULL; + // packer cpp input + if (input->part_number) + { + inputCpp.SetPartNumber(*input->part_number); + } + if (input->upload_id) + { + inputCpp.SetUploadID(input->upload_id); + } + if (input->content_length) + { + inputCpp.SetContentLength(*input->content_length); + } + if (input->content_md5) + { + inputCpp.SetContentMD5(input->content_md5); + } + if (input->x_qs_copy_range) + { + inputCpp.SetXQSCopyRange(input->x_qs_copy_range); + } + if (input->x_qs_copy_source) + { + inputCpp.SetXQSCopySource(input->x_qs_copy_source); + } + if (input->x_qs_copy_source_encryption_customer_algorithm) + { + inputCpp.SetXQSCopySourceEncryptionCustomerAlgorithm(input-> + x_qs_copy_source_encryption_customer_algorithm); + } + if (input->x_qs_copy_source_encryption_customer_key) + { + inputCpp.SetXQSCopySourceEncryptionCustomerKey(input-> + x_qs_copy_source_encryption_customer_key); + } + if (input->x_qs_copy_source_encryption_customer_key_md5) + { + inputCpp.SetXQSCopySourceEncryptionCustomerKeyMD5(input-> + x_qs_copy_source_encryption_customer_key_md5); + } + if (input->x_qs_copy_source_if_match) + { + inputCpp.SetXQSCopySourceIfMatch(input->x_qs_copy_source_if_match); + } + if (input->x_qs_copy_source_if_modified_since) + { + inputCpp.SetXQSCopySourceIfModifiedSince(input-> + x_qs_copy_source_if_modified_since); + } + if (input->x_qs_copy_source_if_none_match) + { + inputCpp.SetXQSCopySourceIfNoneMatch(input-> + x_qs_copy_source_if_none_match); + } + if (input->x_qs_copy_source_if_unmodified_since) + { + inputCpp.SetXQSCopySourceIfUnmodifiedSince(input-> + x_qs_copy_source_if_unmodified_since); + } + if (input->x_qs_encryption_customer_algorithm) + { + inputCpp.SetXQSEncryptionCustomerAlgorithm(input-> + x_qs_encryption_customer_algorithm); + } + if (input->x_qs_encryption_customer_key) + { + inputCpp.SetXQSEncryptionCustomerKey(input-> + x_qs_encryption_customer_key); + } + if (input->x_qs_encryption_customer_key_md5) + { + inputCpp.SetXQSEncryptionCustomerKeyMD5(input-> + x_qs_encryption_customer_key_md5); + } + if (input->bodybuf) + { + reqStreamBody = new QsStream(); + reqStreamBody->write(static_cast < char *>(input->bodybuf), + (size_t) * input->bufLength); + inputCpp.SetBody(reqStreamBody); + } + // init output + init_upload_multipart_output(output); + // call cpp op + Bucket *qsBucket = (Bucket *) (context_hdl.pQsBucket); + QsError err = qsBucket->UploadMultipart(objectKey, inputCpp, outputCpp); + if (QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + int ETagLength = outputCpp.GetETag().length(); + if (ETagLength > 0) + { + output->etag = (char *) malloc(ETagLength + 1); + memset(output->etag, 0, ETagLength + 1); + strncpy(output->etag, outputCpp.GetETag().c_str(), ETagLength); + } + else + { + output->etag = NULL; + } + int XQSContentCopyRangeLength = + outputCpp.GetXQSContentCopyRange().length(); + if (XQSContentCopyRangeLength > 0) + { + output->x_qs_content_copy_range = + (char *) malloc(XQSContentCopyRangeLength + 1); + memset(output->x_qs_content_copy_range, 0, + XQSContentCopyRangeLength + 1); + strncpy(output->x_qs_content_copy_range, + outputCpp.GetXQSContentCopyRange().c_str(), + XQSContentCopyRangeLength); + } + else + { + output->x_qs_content_copy_range = NULL; + } + int XQSEncryptionCustomerAlgorithmLength = + outputCpp.GetXQSEncryptionCustomerAlgorithm().length(); + if (XQSEncryptionCustomerAlgorithmLength > 0) + { + output->x_qs_encryption_customer_algorithm = + (char *) malloc(XQSEncryptionCustomerAlgorithmLength + 1); + memset(output->x_qs_encryption_customer_algorithm, 0, + XQSEncryptionCustomerAlgorithmLength + 1); + strncpy(output->x_qs_encryption_customer_algorithm, + outputCpp.GetXQSEncryptionCustomerAlgorithm().c_str(), + XQSEncryptionCustomerAlgorithmLength); + } + else + { + output->x_qs_encryption_customer_algorithm = NULL; + } + output->response_code = (int) outputCpp.GetResponseCode(); + } + else if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + // if got unexcepted response + output->response_code = (int) outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW << "Got unexcepted response with code:" << errorInfo. + code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + // clean up + if (reqStreamBody) + { + delete reqStreamBody; + reqStreamBody = NULL; + } + return err; +} diff --git a/src/service/service_with_c_style/Types.cpp b/src/service/service_with_c_style/Types.cpp new file mode 100644 index 0000000..633c2d0 --- /dev/null +++ b/src/service/service_with_c_style/Types.cpp @@ -0,0 +1,580 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +// Headers of CustomizedType. +#include "service_with_c_style/Types.h" + +// acl init function. +void init_acl(qs_acl_t * content) +{ + content->grantee = NULL; + content->permission = NULL; +} + +// acl release function. +void release_acl(qs_acl_t * content) +{ + if (content->grantee) + { + release_grantee(content->grantee); + free(content->grantee); + } + if (content->permission) + { + free(content->permission); + } +} + +// bucket init function. +void init_bucket(qs_bucket_t * content) +{ + content->created = NULL; + content->location = NULL; + content->name = NULL; + content->url = NULL; +} + +// bucket release function. +void release_bucket(qs_bucket_t * content) +{ + if (content->created) + { + free(content->created); + } + if (content->location) + { + free(content->location); + } + if (content->name) + { + free(content->name); + } + if (content->url) + { + free(content->url); + } +} + +// condition init function. +void init_condition(qs_condition_t * content) +{ + content->ip_address = NULL; + content->is_null = NULL; + content->not_ip_address = NULL; + content->string_like = NULL; + content->string_not_like = NULL; +} + +// condition release function. +void release_condition(qs_condition_t * content) +{ + if (content->ip_address) + { + release_ip_address(content->ip_address); + free(content->ip_address); + } + if (content->is_null) + { + release_is_null(content->is_null); + free(content->is_null); + } + if (content->not_ip_address) + { + release_not_ip_address(content->not_ip_address); + free(content->not_ip_address); + } + if (content->string_like) + { + release_string_like(content->string_like); + free(content->string_like); + } + if (content->string_not_like) + { + release_string_not_like(content->string_not_like); + free(content->string_not_like); + } +} + +// cors_rule init function. +void init_cors_rule(qs_cors_rule_t * content) +{ + content->allowed_headers = NULL; + content->allowed_methods = NULL; + content->allowed_origin = NULL; + content->expose_headers = NULL; + content->max_age_seconds = NULL; +} + +// cors_rule release function. +void release_cors_rule(qs_cors_rule_t * content) +{ + if (content->allowed_headers) + { + qs_string_item_t *item = NULL; + qs_string_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_string_item_t, item, content->allowed_headers) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(content->allowed_headers); + } + if (content->allowed_methods) + { + qs_string_item_t *item = NULL; + qs_string_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_string_item_t, item, content->allowed_methods) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(content->allowed_methods); + } + if (content->allowed_origin) + { + free(content->allowed_origin); + } + if (content->expose_headers) + { + qs_string_item_t *item = NULL; + qs_string_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_string_item_t, item, content->expose_headers) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(content->expose_headers); + } + if (content->max_age_seconds) + { + free(content->max_age_seconds); + } +} + +// grantee init function. +void init_grantee(qs_grantee_t * content) +{ + content->id = NULL; + content->name = NULL; + content->type = NULL; +} + +// grantee release function. +void release_grantee(qs_grantee_t * content) +{ + if (content->id) + { + free(content->id); + } + if (content->name) + { + free(content->name); + } + if (content->type) + { + free(content->type); + } +} + +// ip_address init function. +void init_ip_address(qs_ip_address_t * content) +{ + content->source_ip = NULL; +} + +// ip_address release function. +void release_ip_address(qs_ip_address_t * content) +{ + if (content->source_ip) + { + qs_string_item_t *item = NULL; + qs_string_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_string_item_t, item, content->source_ip) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(content->source_ip); + } +} + +// is_null init function. +void init_is_null(qs_is_null_t * content) +{ + content->referer = NULL; +} + +// is_null release function. +void release_is_null(qs_is_null_t * content) +{ + if (content->referer) + { + free(content->referer); + } +} + +// key init function. +void init_key(qs_key_t * content) +{ + content->created = NULL; + content->encrypted = NULL; + content->etag = NULL; + content->key = NULL; + content->mime_type = NULL; + content->modified = NULL; + content->size = NULL; +} + +// key release function. +void release_key(qs_key_t * content) +{ + if (content->created) + { + free(content->created); + } + if (content->encrypted) + { + free(content->encrypted); + } + if (content->etag) + { + free(content->etag); + } + if (content->key) + { + free(content->key); + } + if (content->mime_type) + { + free(content->mime_type); + } + if (content->modified) + { + free(content->modified); + } + if (content->size) + { + free(content->size); + } +} + +// key_delete_error init function. +void init_key_delete_error(qs_key_delete_error_t * content) +{ + content->code = NULL; + content->key = NULL; + content->message = NULL; +} + +// key_delete_error release function. +void release_key_delete_error(qs_key_delete_error_t * content) +{ + if (content->code) + { + free(content->code); + } + if (content->key) + { + free(content->key); + } + if (content->message) + { + free(content->message); + } +} + +// not_ip_address init function. +void init_not_ip_address(qs_not_ip_address_t * content) +{ + content->source_ip = NULL; +} + +// not_ip_address release function. +void release_not_ip_address(qs_not_ip_address_t * content) +{ + if (content->source_ip) + { + qs_string_item_t *item = NULL; + qs_string_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_string_item_t, item, content->source_ip) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(content->source_ip); + } +} + +// object_part init function. +void init_object_part(qs_object_part_t * content) +{ + content->created = NULL; + content->etag = NULL; + content->part_number = NULL; + content->size = NULL; +} + +// object_part release function. +void release_object_part(qs_object_part_t * content) +{ + if (content->created) + { + free(content->created); + } + if (content->etag) + { + free(content->etag); + } + if (content->part_number) + { + free(content->part_number); + } + if (content->size) + { + free(content->size); + } +} + +// owner init function. +void init_owner(qs_owner_t * content) +{ + content->id = NULL; + content->name = NULL; +} + +// owner release function. +void release_owner(qs_owner_t * content) +{ + if (content->id) + { + free(content->id); + } + if (content->name) + { + free(content->name); + } +} + +// statement init function. +void init_statement(qs_statement_t * content) +{ + content->action = NULL; + content->condition = NULL; + content->effect = NULL; + content->id = NULL; + content->resource = NULL; + content->user = NULL; +} + +// statement release function. +void release_statement(qs_statement_t * content) +{ + if (content->action) + { + qs_string_item_t *item = NULL; + qs_string_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_string_item_t, item, content->action) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(content->action); + } + if (content->condition) + { + release_condition(content->condition); + free(content->condition); + } + if (content->effect) + { + free(content->effect); + } + if (content->id) + { + free(content->id); + } + if (content->resource) + { + qs_string_item_t *item = NULL; + qs_string_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_string_item_t, item, content->resource) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(content->resource); + } + if (content->user) + { + qs_string_item_t *item = NULL; + qs_string_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_string_item_t, item, content->user) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(content->user); + } +} + +// string_like init function. +void init_string_like(qs_string_like_t * content) +{ + content->referer = NULL; +} + +// string_like release function. +void release_string_like(qs_string_like_t * content) +{ + if (content->referer) + { + qs_string_item_t *item = NULL; + qs_string_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_string_item_t, item, content->referer) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(content->referer); + } +} + +// string_not_like init function. +void init_string_not_like(qs_string_not_like_t * content) +{ + content->referer = NULL; +} + +// string_not_like release function. +void release_string_not_like(qs_string_not_like_t * content) +{ + if (content->referer) + { + qs_string_item_t *item = NULL; + qs_string_item_t *item_to_delete = NULL; + qs_list_for_each_entry(qs_string_item_t, item, content->referer) + { + if (item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + free(item->content); + } + if (item_to_delete) + { + free(item_to_delete); + } + free(content->referer); + } +} + +// uploads init function. +void init_uploads(qs_uploads_t * content) +{ + content->created = NULL; + content->key = NULL; + content->upload_id = NULL; +} + +// uploads release function. +void release_uploads(qs_uploads_t * content) +{ + if (content->created) + { + free(content->created); + } + if (content->key) + { + free(content->key); + } + if (content->upload_id) + { + free(content->upload_id); + } +} diff --git a/src/signer/QsSigner.cpp b/src/signer/QsSigner.cpp new file mode 100644 index 0000000..f3f66d6 --- /dev/null +++ b/src/signer/QsSigner.cpp @@ -0,0 +1,182 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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 "plog/Log.h" +#include "signer/QsSigner.h" +#include "StringUtils.h" +#include "HttpCommon.h" +#include "utils/QsEncoder.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace QingStor; +using namespace QingStor::Utils; +using namespace QingStor::Http; + +static const char* LINE_BREAK = "\n"; +static const char* CANONICALHEADERS_PREFIX = "x-qs-"; + +static const int counToSign = 15; +static std::string pramaterToSign[counToSign] = +{ + "acl", + "cors", + "delete", + "mirror", + "part_number", + "policy", + "stats", + "upload_id", + "uploads", + "response-expires", + "response-cache-control", + "response-content-type", + "response-content-language", + "response-content-encoding", + "response-content-disposition", +}; + +std::string QsSigner::GetTimestamp() const +{ + time_t timestamp; + struct tm *tm_info; + char timebuf[65]; + timestamp = time(NULL); + tm_info = gmtime(×tamp); + strftime(timebuf, 64, "%a, %d %b %Y %H:%M:%S GMT", tm_info); + return std::string(timebuf); +} + +QsError QsSigner::SignRequest(Http::HttpRequest* request) const +{ + /* SHA_DIGEST_LENGTH is 32 */ + char tmpbuf[33]; + std::string timestamp = GetTimestamp(); + request->SetHeaderValue(DATE_HEADER, timestamp); + std::string stringToSign = BuildStringToSign(request); + Encoder::sha256hmac(stringToSign.c_str(), tmpbuf, m_strSecretAccessKey.c_str()); + std::string signature = Encoder::Base64Encode(tmpbuf, 32); // SHA256_DIGEST_LENGHT is 32 + std::string authorization = "QS " + m_AccessKeyID + ":" + signature; + request->SetHeaderValue(AUTHORIZATION_HEADER, authorization); + return QS_ERR_NO_ERROR; +} + + +std::string QsSigner::BuildStringToSign(Http::HttpRequest* request) const +{ + std::string stringToSign; + std::string canonicalizedHeaders; + std::string canonicalizedResource; + stringToSign += HttpMethodMapper::GetNameForHttpMethod(request->GetMethod()); + stringToSign += LINE_BREAK; + stringToSign += request->GetHeaderValue(CONTENT_MD5_HEADER); + stringToSign += LINE_BREAK; + stringToSign += request->GetHeaderValue(CONTENT_TYPE_HEADER); + stringToSign += LINE_BREAK; + stringToSign += request->GetHeaderValue(DATE_HEADER); + stringToSign += LINE_BREAK; + canonicalizedHeaders = BuildCanonicalizedHeaders(request->GetHeaders()); + stringToSign += canonicalizedHeaders; + canonicalizedResource = BuildCanonicalizedResource(request->GetQueries(), request->GetURLEncodedPath()); + stringToSign += canonicalizedResource; + LOG_DEBUG << "QingStor string to sign:" << stringToSign; + return stringToSign; +} + +std::string QsSigner::BuildCanonicalizedHeaders(Http::HeaderValueCollection headers) const +{ + std::stringstream ssCanonicalHeaders; + std::vector arrayCanonicalHeaders; + for(HeaderValueCollection::iterator it = headers.begin(); it != headers.end(); it++) + { + // skip header wiht "" value + if ("" != it->second) + { + std::string strHeaderKey = StringUtils::ToLower(it->first.c_str()); + if (StringUtils::HasPrefix(strHeaderKey, CANONICALHEADERS_PREFIX)) + { + arrayCanonicalHeaders.push_back(strHeaderKey); + } + } + } + // sort with from small to big, Alphabetic order   + std::sort(arrayCanonicalHeaders.begin(), arrayCanonicalHeaders.end(), std::less()); + for(std::vector::iterator it = arrayCanonicalHeaders.begin(); it != arrayCanonicalHeaders.end(); it++) + { + ssCanonicalHeaders << *it << ":" << headers[*it] << LINE_BREAK; + } + return ssCanonicalHeaders.str(); +} + +std::string QsSigner::BuildCanonicalizedResource(QueryParamCollection queryMap, std::string urlEncodedPath) const +{ + // filter + std::vector arrayQueryParams; + for (QueryParamCollection::iterator iter = queryMap.begin(); + iter != queryMap.end(); ++iter) + { + bool isParameterToSigner = false; + for (int i = 0; i < counToSign; i++) + { + if (iter->first == pramaterToSign[i]) + { + // chose to sign + isParameterToSigner = true; + break; + } + } + if (!isParameterToSigner) + { + continue; + } + arrayQueryParams.push_back(iter->first); + } + std::stringstream signingStringStream; + signingStringStream << urlEncodedPath; + bool first = true; + // sort with from small to big, Alphabetic order + std::sort(arrayQueryParams.begin(), arrayQueryParams.end(), std::less()); + for(std::vector::iterator it = arrayQueryParams.begin(); it != arrayQueryParams.end(); it++) + { + if (!first) + { + signingStringStream << "&"; + } + else + { + signingStringStream << "?"; + } + first = false; + std::string queryName = *it; + std::string queryValue = queryMap[queryName]; + signingStringStream << queryName; + if ("" != queryValue) + { + signingStringStream << "="; + signingStringStream << queryValue; + } + } + return signingStringStream.str(); +} \ No newline at end of file diff --git a/src/utils/QsEncoder.cpp b/src/utils/QsEncoder.cpp new file mode 100644 index 0000000..1efdfef --- /dev/null +++ b/src/utils/QsEncoder.cpp @@ -0,0 +1,72 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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 "utils/QsEncoder.h" +#include +#include + +#include +#include +#include +#include +#include + +namespace QingStor +{ +namespace Utils +{ +namespace Encoder +{ +/* Encodes a binary safe base 64 string */ +std::string Base64Encode(const char *buffer, size_t length) +{ + BIO *bio, *b64; + BUF_MEM *bufferPtr; + char *ret; + b64 = BIO_new(BIO_f_base64()); + bio = BIO_new(BIO_s_mem()); + bio = BIO_push(b64, bio); + BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); // Ignore newlines - write + // everything in one line + BIO_write(bio, buffer, length); + (void) BIO_flush(bio); + BIO_get_mem_ptr(bio, &bufferPtr); + ret = (char *) malloc(bufferPtr->length + 1); + memcpy(ret, bufferPtr->data, bufferPtr->length); + ret[bufferPtr->length] = 0; + (void) BIO_set_close(bio, BIO_NOCLOSE); + BIO_free_all(bio); + std::string strEncoded(ret); + free(ret); +#ifndef _WIN32 + free(bufferPtr->data); + free(bufferPtr); +#endif + return strEncoded; +} + + +void sha256hmac(const char *str, char out[33], const char *secret) +{ + unsigned int len = 32; + (void)HMAC(EVP_sha256(), secret, strlen(secret), (unsigned char *)str, strlen(str), (unsigned char *)out, &len); + out[32] = '\0'; + return; +} + +} +} // namespace Utils +} // namespace QingStor \ No newline at end of file diff --git a/src/utils/StringUtils.cpp b/src/utils/StringUtils.cpp new file mode 100644 index 0000000..98dbae1 --- /dev/null +++ b/src/utils/StringUtils.cpp @@ -0,0 +1,260 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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 "StringUtils.h" +#include +#include +#include +#include +#include +#include +#include + +using namespace QingStor::Utils; + +#ifdef _WIN32 + +std::wstring StringUtils::ToWString(const char* source) +{ + std::wstring outString; + outString.resize(std::strlen(source)); + std::copy(source, source + std::strlen(source), outString.begin()); + return outString; +} + +std::string StringUtils::FromWString(const wchar_t* source) +{ + std::wstring inWString(source); + std::string outString(inWString.begin(), inWString.end()); + return outString; +} + +#endif + +bool StringUtils::HasPrefix(std::string& s, const char* prefix) +{ + if (!prefix) + { + return false; + } + std::size_t pos = 0; + pos = s.find(prefix, pos); + return (pos != std::string::npos); +} + +void StringUtils::Replace(std::string& s, const char* search, const char* replace) +{ + if(!search || !replace) + { + return; + } + size_t replaceLength = strlen(replace); + size_t searchLength = strlen(search); + for (std::size_t pos = 0;; pos += replaceLength) + { + pos = s.find(search, pos); + if (pos == std::string::npos) + break; + s.erase(pos, searchLength); + s.insert(pos, replace); + } +} + + +std::string StringUtils::ToLower(const char* source) +{ + std::string copy; + size_t sourceLength = strlen(source); + for(size_t i = 0; i < sourceLength; i++) + { + copy += tolower(source[i]); + } + return copy; +} + + +std::string StringUtils::ToUpper(const char* source) +{ + std::string copy; + size_t sourceLength = strlen(source); + for(size_t i = 0; i < sourceLength; i++) + { + copy += toupper(source[i]); + } + return copy; +} + + +bool StringUtils::CaselessCompare(const char* value1, const char* value2) +{ + std::string value1Lower = ToLower(value1); + std::string value2Lower = ToLower(value2); + return value1Lower == value2Lower; +} + + +std::vector StringUtils::Split(const std::string& toSplit, char splitOn) +{ + // std::stringstream input(toSplit.c_str()); + std::stringstream ss; + ss << toSplit; + std::vector returnValues; + std::string item; + while (std::getline(ss, item, splitOn)) + { + if(item.size() > 0) + { + returnValues.push_back(item); + } + } + return returnValues; +} + + +std::string StringUtils::URLEncode(const char* unsafe) +{ + std::stringstream escaped; + escaped.fill('0'); + escaped << std::hex << std::uppercase; + size_t unsafeLength = strlen(unsafe); + const char * i; + const char * n; + n = unsafe + unsafeLength; + for ( i = unsafe ; i != n; ++i) + { + int c = *i; + //MSVC 2015 has an assertion that c is positive in isalnum(). This breaks unicode support. + //bypass that with the first check. + if (c >= 0 && (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~' || c == '=') ) + { + escaped << (char)c; + } + else + { + //this unsigned char cast allows us to handle unicode characters. + escaped << '%' << std::setw(2) << int((unsigned char)c) << std::setw(0); + } + } + return escaped.str(); +} + +std::string StringUtils::URLEncode(double unsafe) +{ + char buffer[32]; +#if defined(_MSC_VER) && _MSC_VER < 1900 + _snprintf_s(buffer, sizeof(buffer), _TRUNCATE, "%g", unsafe); +#else + snprintf(buffer, sizeof(buffer), "%g", unsafe); +#endif + return StringUtils::URLEncode(buffer); +} + + +std::string StringUtils::URLDecode(const char* safe) +{ + std::stringstream unescaped; + unescaped.fill('0'); + unescaped << std::hex; + size_t safeLength = strlen(safe); + const char* n = safe + safeLength; + for (const char* i = safe; i != n; ++i) + { + char c = *i; + if(c == '%') + { + char hex[3]; + hex[0] = *(i + 1); + hex[1] = *(i + 2); + hex[2] = 0; + i += 2; + long int hexAsInteger = strtol(hex, NULL, 16); + unescaped << (char)hexAsInteger; + } + else + { + unescaped << *i; + } + } + return unescaped.str(); +} + +std::string StringUtils::LTrim(const char* source) +{ + std::string copy(source); + copy.erase(copy.begin(), std::find_if(copy.begin(), copy.end(), std::not1(std::ptr_fun(::isspace)))); + return copy; +} + +// trim from end +std::string StringUtils::RTrim(const char* source) +{ + std::string copy(source); + copy.erase(std::find_if(copy.rbegin(), copy.rend(), std::not1(std::ptr_fun(::isspace))).base(), copy.end()); + return copy; +} + +// trim from both ends +std::string StringUtils::Trim(const char* source) +{ + return LTrim(RTrim(source).c_str()); +} + +long long StringUtils::ConvertToInt64(const char* source) +{ + if(!source) + { + return 0; + } + return std::atoll(source); +} + + +long StringUtils::ConvertToInt32(const char* source) +{ + if (!source) + { + return 0; + } + return std::atol(source); +} + + +bool StringUtils::ConvertToBool(const char* source) +{ + if(!source) + { + return false; + } + std::string strValue = ToLower(source); + if(strValue == "true" || strValue == "1") + { + return true; + } + return false; +} + + +double StringUtils::ConvertToDouble(const char* source) +{ + if(!source) + { + return 0.0; + } + return std::strtod(source, NULL); +} + + + diff --git a/template/header/manifest.json b/template/header/manifest.json new file mode 100644 index 0000000..1c091a6 --- /dev/null +++ b/template/header/manifest.json @@ -0,0 +1,42 @@ +{ + + "output": { + "file_naming": { + "style": "camel_case", + "extension": ".h" + } + }, + "template_files": { + "shared": { + "file_path": "shared.tmpl" + }, + "service": { + "file_path": "service.tmpl", + "output_file_naming": { + "prefix": "", + "suffix": "" + } + }, + "sub_service": { + "file_path": "sub_service.tmpl", + "output_file_naming": { + "prefix": "", + "suffix": "" + } + }, + "types": { + "file_path": "types.tmpl", + "output_file_naming": { + "prefix": "", + "suffix": "" + } + }, + "types_cpp": { + "file_path": "types_cpp.tmpl", + "output_file_naming": { + "prefix": "", + "suffix": "Type" + } + } + } +} diff --git a/template/header/service.tmpl b/template/header/service.tmpl new file mode 100644 index 0000000..8ff97fd --- /dev/null +++ b/template/header/service.tmpl @@ -0,0 +1,93 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +{{$service := .Data.Service}} +{{$className := $service.Name}} +#pragma once + +#include "QsSdkOption.h" +#include "Bucket.h" + +namespace QingStor +{ + +// SDK wide options +struct QS_SDK_API SDKOptions +{ + SDKOptions():initAndCleanupCurl(true), logLevel(None), logPath("") + { + } + // SDK wide options for curl + // If it is being used then we automatically initialize and clean it up. + // If this is a problem for you, set this to false. + bool initAndCleanupCurl; + + // Option for logging level ,defaults to Off + LogLevel logLevel; + + // Option for logging file path, defaults to the path of the executable program. + std::string logPath; +}; + +// This method should be called brfore using the SDK. +QS_SDK_API void InitializeSDK(const SDKOptions & options); + +// This method should be called when you are finished using the SDK. +// Do not call any other SDK methods after calling ShutdownSDK. +QS_SDK_API void ShutdownSDK(const SDKOptions & options); + + +// +-------------------------------------------------------------------- +// | InputClassHeader +// +-------------------------------------------------------------------- +{{- range $_, $operation := $service.Operations}} +{{template "InputClassHeader" passThrough $service $operation}} +{{- end}} + + +// +-------------------------------------------------------------------- +// | OutputClassHeader +// +-------------------------------------------------------------------- + +{{- range $_, $operation := $service.Operations}} +{{template "OutputClassHeader" passThrough $service $operation}} +{{- end}} + +// +-------------------------------------------------------------------- +// | {{$className}}Service +// +-------------------------------------------------------------------- + +class QS_SDK_API QingStorService +{ + public: + QingStorService(const QsConfig &qsConfig); + + virtual ~QingStorService(){}; + + // ListBuckets does Retrieve the bucket list. + // Documentation URL: https://docs.qingcloud.com/qingstor/api/service/get.html + QsError ListBuckets(ListBucketsInput &input, + ListBucketsOutput &output); + + private: + QsConfig m_qsConfig; + Properties m_properties; +}; + + +}// namespace QingStor + + diff --git a/template/header/shared.tmpl b/template/header/shared.tmpl new file mode 100644 index 0000000..85b533e --- /dev/null +++ b/template/header/shared.tmpl @@ -0,0 +1,683 @@ +{{define "RenderPropertiesFlags"}} +{{- $operation := index . 0 -}} +{{- $propertys := index . 1 -}} + + {{range $idx, $property := $propertys -}} + {{- if $property.Description}} +// {{$property.Description}}'flag + {{- end}} + {{- if $property.Enum}} +// {{$property.ID | camelCase}}'s available values: {{$property.Enum | commaConnected}} + {{- end}} +#define SETTING_{{$operation.ID | snakeCase | upper}}_{{$property.ID | snakeCase | upper}}_FLAG 0x{{hexCodePowerOf2 $idx}} + {{end}} +{{end}} + +{{define "RenderInputPropertiesFlags"}} +{{- $operation := index . 0 -}} +{{- $propertys := index . 1 -}} + + {{range $idx, $property := $propertys -}} + {{- if $property.Description}} + // {{$property.Description}}'flag + {{- end}} + {{- if $property.Enum}} + // {{$property.ID | camelCase}}'s available values: {{$property.Enum | commaConnected}} + {{- end}} +#define SETTING_INPUT_{{$operation.ID | snakeCase | upper}}_{{$property.ID | snakeCase | upper}}_FLAG 0x{{hexCodePowerOf2 $idx}} + {{end}} +{{end}} + + +{{define "RenderOutputPropertiesFlags"}} +{{- $operation := index . 0 -}} +{{- $propertys := index . 1 -}} + + {{range $idx, $property := $propertys -}} + {{- if $property.Description}} + // {{$property.Description}}'flag + {{- end}} + {{- if $property.Enum}} + // {{$property.ID | camelCase}}'s available values: {{$property.Enum | commaConnected}} + {{- end}} +#define SETTING_OUTPUT_{{$operation.ID | snakeCase | upper}}_{{$property.ID | snakeCase | upper}}_FLAG 0x{{hexCodePowerOf2 $idx}} + {{end}} +{{end}} + + +{{define "RequestDeclaration"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | camelCase -}} + class{{" " -}}{{- $opID -}}Request; +{{end}} + +{{define "ResultDeclaration"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | camelCase -}} + class{{" " -}}{{- $opID -}}Result; +{{end}} + +{{define "OperationDeclaration"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | camelCase -}} + {{- $belongs := replace $service.Name "QingStor" "Service" -1 -}} + {{- $belongs := replace $belongs "Object" "Bucket" -1 -}} + {{- $isBucket := eq $service.Name "Bucket" -}} + {{- $isObject := eq $service.Name "Object" -}} + {{- $operationName := $opID}} + + {{if $operation.Description -}} + {{if eq $belongs "Bucket" -}} + // {{replace $opID "Bucket" "" -1}} does {{$operation.Description -}} + {{else -}} + // {{$opID}} does {{$operation.Description -}} + {{end -}} + {{- end}} + {{if $operation.DocumentationURL -}} + // Documentation URL: {{$operation.DocumentationURL}} + {{- end}} + QsError {{$operationName}}({{- if $isObject}}std::string objectKey, {{end -}}{{$operation.ID}}Input& input, {{$operation.ID}}Output& output); +{{end}} + +{{define "RenderRequestEnumPramasID"}} + {{- $operation := index . 0 -}} + + enum class {{$operation.ID | upper}}_REQUSET_PARAMS_ID + { + {{- if $operation.Request.Query.Properties | len}} + {{range $_, $propertyParams := $operation.Request.Query.Properties -}} + {{$propertyParams.ID | camelCase | upper}}_ID; + {{end}} + {{end}} + {{- if $operation.Request.Headers.Properties | len}} + {{range $_, $propertyHeaders := $operation.Request.Headers.Properties -}} + {{$propertyHeaders.ID | camelCase | upper}}_ID; + {{end}} + {{end}} + {{- if $operation.Request.Elements.Properties | len}} + {{range $_, $propertyElements := $operation.Request.Elements.Properties -}} + {{$propertyElements.ID | camelCase | upper}}_ID; + {{end}} + {{end -}} + }; +{{end}} + + +{{define "InputCStyleHeader"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | camelCase -}} + {{- $belongs := replace $service.Name "QingStor" "Service" -1 -}} + {{- $belongs := replace $belongs "Object" "Bucket" -1}} + {{- $uri := $operation.Request.Path}} + {{- $uri := replace $uri "{" "<" -1}} + {{- $uri := replace $uri "}" ">" -1}} + {{- $uri := dashConnected $uri}} + {{- $hasHeaders := gt (len $operation.Request.Headers.Properties) 0 -}} + {{- $hasElements := gt (len $operation.Request.Elements.Properties) 0 -}} + {{- $hasParams := gt (len $operation.Request.Query.Properties) 0 -}} + {{- $hasStringBody := eq $operation.Request.Body.Type "string" -}} + {{- $hasBinaryBody := eq $operation.Request.Body.Type "binary" -}} + {{- $hasInput := or $hasHeaders $hasElements $hasParams $hasStringBody $hasBinaryBody}} + +{{- if $hasInput}} +// {{$opID}}Input presents input for {{$opID}}. +typedef struct { + + {{- if $hasParams}} + {{$data := $operation.Request.Query -}} + {{template "RenderCStyleProperties" passThrough $data `location:"params"` $operation.Name}} + {{end -}} + {{- if $hasHeaders}} + {{- $data := $operation.Request.Headers -}} + {{template "RenderCStyleProperties" passThrough $data `location:"headers"` $operation.Name}} + {{end -}} + {{- if $hasElements}} + {{- $data := $operation.Request.Elements -}} + {{template "RenderProperties" passThrough $data `location:"elements"` $operation.Name}} + {{end -}} + {{- if $hasStringBody -}} + {{- if $operation.Request.Body.Description -}} + // {{$operation.Request.Body.Description}} + {{- end}} + std::stringstream body; + {{- else if $hasBinaryBody -}} + {{- if $operation.Request.Body.Description -}} + // {{$operation.Request.Body.Description}} + {{- end}} + std::iostream body; + {{- end}} + + +} {{$opID}}Input; + + +class QS_SDK_API {{$opID}}Input:public QsBaseInput +{ +public: + {{- if $hasParams}} + {{$data := $operation.Request.Query -}} + {{template "RenderInputInlineFuncs" passThrough $data `location:"params"` $operation.ID}} + {{end}} + + {{- if $hasHeaders}} + {{$data := $operation.Request.Headers -}} + {{template "RenderInputInlineFuncs" passThrough $data `location:"headers"` $operation.ID}} + {{end}} + + {{- if $hasElements}} + {{$data := $operation.Request.Elements -}} + {{template "RenderInputInlineFuncs" passThrough $data `location:"elements"` $operation.ID}} + {{end}} + +private: + + {{- if $hasParams}} + {{$data := $operation.Request.Query -}} + {{template "RenderProperties" passThrough $data `location:"params"` $operation.Name}} + {{end -}} + {{- if $hasHeaders}} + {{- $data := $operation.Request.Headers -}} + {{template "RenderProperties" passThrough $data `location:"headers"` $operation.Name}} + {{end -}} + {{- if $hasElements}} + {{- $data := $operation.Request.Elements -}} + {{template "RenderProperties" passThrough $data `location:"elements"` $operation.Name}} + {{end -}} + {{- if $hasStringBody -}} + {{- if $operation.Request.Body.Description -}} + // {{$operation.Request.Body.Description}} + {{- end}} + std::stringstream body; + {{- else if $hasBinaryBody -}} + {{- if $operation.Request.Body.Description -}} + // {{$operation.Request.Body.Description}} + {{- end}} + std::iostream body; + {{- end}} + +}; +{{- else -}} +typedef QsBaseInput {{$opID}}Input; +{{- end -}} +{{- end -}} + + +{{define "InputClassHeader"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | camelCase -}} + {{- $belongs := replace $service.Name "QingStor" "Service" -1 -}} + {{- $belongs := replace $belongs "Object" "Bucket" -1}} + {{- $uri := $operation.Request.Path}} + {{- $uri := replace $uri "{" "<" -1}} + {{- $uri := replace $uri "}" ">" -1}} + {{- $uri := dashConnected $uri}} + {{- $hasHeaders := gt (len $operation.Request.Headers.Properties) 0 -}} + {{- $hasElements := gt (len $operation.Request.Elements.Properties) 0 -}} + {{- $hasParams := gt (len $operation.Request.Query.Properties) 0 -}} + {{- $hasStringBody := eq $operation.Request.Body.Type "string" -}} + {{- $hasBinaryBody := eq $operation.Request.Body.Type "binary" -}} + {{- $hasInput := or $hasHeaders $hasElements $hasParams $hasStringBody $hasBinaryBody -}} + +// {{$opID}}Input presents input for {{$opID}}. +{{- if $hasInput}} +class QS_SDK_API {{$opID}}Input:public QsInput +{ +public: + {{$opID}}Input(){{- if $hasBinaryBody -}}:m_streambody(NULL){{- end -}}{}; + + inline bool CheckIfInputIsVaild() + { + int tmpFlag = BASIC_FLAG {{- if $hasParams}} + {{- range $_, $paramsProperty := $operation.Request.Query.Properties -}} + {{- if $paramsProperty.IsRequired}}|SETTING_INPUT_{{$operation.ID |snakeCase |upper}}_{{$paramsProperty.ID |snakeCase |upper}}_FLAG{{end}} + {{- end -}} + {{- end -}} + {{- if $hasHeaders}} + {{- range $_, $headersProperty := $operation.Request.Headers.Properties -}} + {{- if $headersProperty.IsRequired}}| SETTING_INPUT_{{$operation.ID |snakeCase |upper}}_{{$headersProperty.ID|snakeCase |upper }}_FLAG {{end}} + {{- end -}} + {{- end -}} + {{- if $hasElements}} + {{- range $_, $elementsProperty := $operation.Request.Elements.Properties -}} + {{- if $elementsProperty.IsRequired}}| SETTING_INPUT_{{$operation.ID |snakeCase |upper}}_{{$elementsProperty.ID |snakeCase |upper}}_FLAG {{end -}} + {{- end -}} + {{- end -}}; + return (tmpFlag == (tmpFlag & m_settingFlag)); + }; + {{- if $hasParams}} + {{$data := $operation.Request.Query -}} + {{template "RenderInputInlineFuncs" passThrough $data `location:"params"` $operation.ID}} + {{end}} + + {{- if $hasHeaders}} + {{$data := $operation.Request.Headers -}} + {{template "RenderInputInlineFuncs" passThrough $data `location:"headers"` $operation.ID}} + {{end}} + + {{- if $hasElements}} + {{$data := $operation.Request.Elements -}} + {{template "RenderInputInlineFuncs" passThrough $data `location:"elements"` $operation.ID}} + {{end}} + + {{- if $hasBinaryBody}} + std::iostream* GetBody(){ return m_streambody;}; + void SetBody(std::iostream * streambody){ m_streambody = streambody;}; + {{end -}} + +private: + + {{- if $hasParams}} + {{$data := $operation.Request.Query -}} + {{template "RenderProperties" passThrough $data `location:"params"` $operation.Name}} + {{end -}} + {{- if $hasHeaders}} + {{- $data := $operation.Request.Headers -}} + {{template "RenderProperties" passThrough $data `location:"headers"` $operation.Name}} + {{end -}} + {{- if $hasElements}} + {{- $data := $operation.Request.Elements -}} + {{template "RenderProperties" passThrough $data `location:"elements"` $operation.Name}} + {{end -}} + {{- if $hasBinaryBody}} + std::iostream* m_streambody; + {{end -}} + +}; +{{- else}} +typedef QsInput {{$opID}}Input; +{{- end -}} +{{- end -}} + +{{define "OutputClassHeader"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | camelCase -}} + {{- $belongs := replace $service.Name "QingStor" "Service" -1 -}} + {{- $belongs := replace $belongs "Object" "Bucket" -1}} + {{- $hasRespHeaders := gt (len (allRespnoseHeaders $operation.Responses)) 0 -}} + {{- $hasRespElements := gt (len (allRespnoseElements $operation.Responses)) 0 -}} + {{- $responseBody := getRespnosesBody $operation.Responses -}} + {{- $hasRespStringBody := eq $responseBody.Type "string" -}} + {{- $hasRespBinaryBody := eq $responseBody.Type "binary" -}} + {{- $hasOutput := or $hasRespHeaders $hasRespElements $hasRespStringBody $hasRespBinaryBody}} + +{{- if $hasOutput}} +// {{$opID}}Output presents input for {{$opID}}. +class QS_SDK_API {{$opID}}Output: public QsOutput +{ + +public: + {{$opID}}Output(QsError err, Http::HttpResponseCode responseCode):QsOutput(err, responseCode){}; + {{$opID}}Output(){}; +{{- range $_, $Response := $operation.Responses}} + + {{- if $Response.Headers.Properties | len}} + {{$data := $Response.Headers -}} + {{template "RenderOutputInlineFuncs" passThrough $data `location:"headers"` $operation.ID}} + {{end}} + + {{- if $Response.Elements.Properties | len}} + {{$data := $Response.Elements -}} + {{template "RenderOutputInlineFuncs" passThrough $data `location:"elements"` $operation.ID}} + {{end}} + {{- if eq $Response.Body.Type "binary"}} + std::iostream* GetBody(){ return m_streambody;}; + void SetBody(std::iostream* streambody){ m_streambody = streambody;}; + {{end -}} + +{{end}} + +private: + +{{- range $_, $Response := $operation.Responses}} + + {{- if $Response.Headers.Properties | len}} + {{- $data := $Response.Headers -}} + {{template "RenderProperties" passThrough $data `location:"headers"` $operation.Name}} + {{end -}} + {{- if $Response.Elements.Properties | len}} + {{- $data := $Response.Elements -}} + {{template "RenderProperties" passThrough $data `location:"elements"` $operation.Name}} + {{end -}} + {{- if eq $Response.Body.Type "binary"}} + std::iostream* m_streambody; + {{end}} + +{{end}} +}; +{{- else}} +typedef QsOutput {{$opID}}Output; +{{- end -}} +{{- end -}} + + +{{define "RenderInputInlineFuncs"}} + {{- $customizedType := index . 0 -}} + {{- $propertyExtraTags := index . 1 -}} + {{- $operationName := index . 2 -}} + + {{range $_, $property := $customizedType.Properties -}} + {{if $property.Description -}} + // {{$property.Description}} + {{- end -}} + {{if $property.Enum -}} + // {{$property.ID | camelCase}}'s available values: {{$property.Enum | commaConnected}} + {{- end}} + + {{- $isNotString := ne $property.Type "string" -}} + {{- $isNotInteger := ne $property.Type "integer" -}} + {{- $isNotLong := ne $property.Type "long" -}} + {{- if and (and $isNotString $isNotInteger) $isNotLong}} +#ifdef BUILD_C_STYLE_INTERFACE + inline void Set{{$property.ID | camelCase}}({{template "CStylePropertyType" passThrough $property false}} {{" " -}} {{$property.ID | snakeCase}}) + { + {{if eq $property.Type "array"}} + qs_{{$property.ExtraType | snakeCase}}_item_t * item; + + qs_list_for_each_entry(qs_{{$property.ExtraType | snakeCase}}_item_t, item, {{$property.ID | snakeCase}}) + { + m_{{$property.ID | camelCase | upperFirst}}.push_back(*item->content); + } + {{else}} + m_{{$property.ID | camelCase | upperFirst}} = {{$property.ID | snakeCase}}; + {{end}} + }; +#endif // BUILD_C_STYLE_INTERFACE + {{- end}} + + inline void Set{{$property.ID | camelCase}}({{template "RequestPropertyType" passThrough $property false}}{{" " -}} {{$property.ID | camelCase}}) + { + m_settingFlag |= SETTING_INPUT_{{$operationName | snakeCase |upper}}_{{$property.ID | snakeCase | upper}}_FLAG; + m_{{$property.ID | camelCase | upperFirst}} = {{$property.ID | camelCase}}; + }; + + inline {{template "RequestPropertyType" passThrough $property false}} Get{{$property.ID | camelCase}}(){return m_{{$property.ID | camelCase | upperFirst}};}; + {{end -}} +{{end}} + +{{define "RenderOutputInlineFuncs"}} + {{- $customizedType := index . 0 -}} + {{- $propertyExtraTags := index . 1 -}} + {{- $operationName := index . 2 -}} + + {{range $_, $property := $customizedType.Properties -}} + {{- if $property.Description}} + // {{$property.Description}} + {{- end -}} + {{if $property.Enum -}} + // {{$property.ID | camelCase}}'s available values: {{$property.Enum | commaConnected}} + {{- end}} + inline void Set{{$property.ID | camelCase}}({{template "RequestPropertyType" passThrough $property false}}{{" " -}} {{$property.ID | camelCase}}) + { + m_settingFlag |= SETTING_OUTPUT_{{$operationName | snakeCase |upper}}_{{$property.ID | snakeCase | upper}}_FLAG; + m_{{$property.ID | camelCase | upperFirst}} = {{$property.ID | camelCase}}; + }; + + inline {{template "RequestPropertyType" passThrough $property false}} Get{{$property.ID | camelCase}}(){return m_{{$property.ID | camelCase | upperFirst}};}; + {{end -}} +{{end}} + +{{define "RenderCStyleProperties"}} + {{- $customizedType := index . 0 -}} + {{- $propertyExtraTags := index . 1 -}} + {{- $operationName := index . 2 -}} + + {{range $_, $property := $customizedType.Properties -}} + {{- if $property.Description}} + // {{$property.Description}} + {{- end}} + {{- if $property.Enum -}} + // {{$property.ID | camelCase}}'s available values: {{$property.Enum | commaConnected}} + {{- end}} + {{template "RequestPropertyType" passThrough $property false}}{{" " -}}m_{{$property.ID | camelCase | upperFirst}}{{";" -}} + {{- if $property.IsRequired -}} + // Required + {{- end}} + {{end}} +{{end}} + + +{{define "RenderProperties"}} + {{- $customizedType := index . 0 -}} + {{- $propertyExtraTags := index . 1 -}} + {{- $operationName := index . 2 -}} + + {{range $_, $property := $customizedType.Properties -}} + {{- if $property.Description}} + // {{$property.Description}} + {{- end}} + {{- if $property.Enum}} + // {{$property.ID | camelCase}}'s available values: {{$property.Enum | commaConnected}} + {{- end}} + {{template "RequestPropertyType" passThrough $property false}}{{" " -}}m_{{$property.ID | camelCase | upperFirst}}{{";" -}} + {{- if $property.IsRequired -}} + // Required + {{- end}} + {{end}} +{{end}} + + +{{define "RequestCStylePropertyType"}} + {{- $property := index . 0 -}} + {{- $disablePointer := index . 1 -}} + + {{- if eq $property.Type "object"}} + {{$property.ID | camelCase}}Type + {{- else if eq $property.Type "array"}} + std::vector<{{template "Type" passThrough $property.ExtraType $disablePointer}}> + {{- else if eq $property.Type "map"}} + Map[string]{{template "Type" passThrough $property.ExtraType $disablePointer}} + {{- else if eq $property.Type "any"}} + {{- template "Type" passThrough $property.Type $disablePointer}} + {{- else -}} + {{- template "Type" passThrough $property.Type $disablePointer}} + {{- end -}} +{{end}} + +{{define "CStylePropertyType"}} + {{- $property := index . 0 -}} + {{- $disablePointer := index . 1 -}} + + {{- if eq $property.Type "object"}} + {{template "TypeWithCStyle" passThrough $property.ExtraType $disablePointer}} + {{- else if eq $property.Type "array"}} + qs_list_t * + {{- else if eq $property.Type "map"}} + // "C wit map??????????????????????" + {{- else if eq $property.Type "any"}} + {{template "TypeWithCStyle" passThrough $property.Type $disablePointer}} + {{- else -}} + {{template "TypeWithCStyle" passThrough $property.Type $disablePointer}} + {{- end -}} +{{end}} + +{{define "TypeWithCStyle"}} + {{- $typeName := index . 0 -}} + {{- $disablePointer := index . 1 -}} + + {{- if eq $typeName "string" -}} + char* {{" " -}} + {{- else if eq $typeName "boolean" -}} + int * {{" " -}} + {{- else if eq $typeName "integer" -}} + int *{{" " -}} + {{- else if eq $typeName "long" -}} + int64_t *{{" " -}} + {{- else if eq $typeName "timestamp" -}} + char* {{" " -}} + {{- else if eq $typeName "binary" -}} + void *{" " -}} + {{- else if eq $typeName "array" -}} + qs_list_t * + {{- else if eq $typeName "object" -}} + interface{} + {{- else if eq $typeName "map" -}} + interface{} + {{- else if eq $typeName "any" -}} + interface{} + {{- else -}} + qs_{{$typeName}}_t *{{" " -}} + {{- end -}} +{{end}} + +{{define "RequestPropertyType"}} + {{- $property := index . 0 -}} + {{- $disablePointer := index . 1 -}} + + {{- if eq $property.Type "object"}} + {{$property.ID | camelCase}}Type + {{- else if eq $property.Type "array"}} + std::vector<{{template "Type" passThrough $property.ExtraType $disablePointer}}> + {{- else if eq $property.Type "map"}} + Map[string]{{template "Type" passThrough $property.ExtraType $disablePointer}} + {{- else if eq $property.Type "any"}} + {{- template "Type" passThrough $property.Type $disablePointer}} + {{- else -}} + {{- template "Type" passThrough $property.Type $disablePointer}} + {{- end -}} +{{end}} + + +{{define "RenderResultInlineFuncs"}} + {{- $customizedType := index . 0 -}} + {{- $propertyExtraTags := index . 1 -}} + {{- $operationName := index . 2 -}} + + {{range $_, $property := $customizedType.Properties -}} + {{if $property.Description -}} + // {{$property.Description}} + {{- end}} + {{if $property.Enum -}} + // {{$property.ID | camelCase}}'s available values: {{$property.Enum | commaConnected}} + {{- end}} + inline const {{template "RequestPropertyType" passThrough $property false}} Get{{$property.ID | camelCase}}(){return m_{{$property.ID | camelCase}}}; + {{end}} +{{end}} + +{{define "ResultHeader"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | camelCase -}} + {{- $belongs := replace $service.Name "QingStor" "Service" -1 -}} + {{- $belongs := replace $belongs "Object" "Bucket" -1}} + {{- $hasHeaders := gt (len $operation.Response.Headers.Properties) 0 -}} + {{- $hasElements := gt (len $operation.Response.Elements.Properties) 0 -}} + {{- $hasStringBody := eq $operation.Response.Body.Type "string" -}} + {{- $hasBinaryBody := eq $operation.Response.Body.Type "binary" -}} + {{- $hasInput := or $hasHeaders $hasElements $hasStringBody $hasBinaryBody -}} + + {{- if $hasInput}} +// {{$opID}}Result presents output for {{$opID}}. +class {{$opID}}Result : public QSRequest +{ +public: + {{- if $operation.Response.Headers.Properties | len}} + {{$data := $operation.Response.Headers -}} + {{template "RenderResultInlineFuncs" passThrough $data `location:"headers"` $operation.Name}} + {{end}} + + {{- if $operation.Response.Elements.Properties | len}} + {{$data := $operation.Response.Elements -}} + {{template "RenderResultInlineFuncs" passThrough $data `location:"elements"` $operation.Name}} + {{end}} + +private: + {{- if $operation.Response.Headers.Properties | len}} + {{- $data := $operation.Response.Headers -}} + {{template "RenderProperties" passThrough $data `location:"headers"` $operation.Name}} + {{end}} + {{- if $operation.Response.Elements.Properties | len}} + {{- $data := $operation.Response.Elements -}} + {{template "RenderProperties" passThrough $data `location:"elements"` $operation.Name}} + {{end -}} + {{- if eq $operation.Response.Body.Type "string" -}} + {{- if $operation.Response.Body.Description -}} + // {{$operation.Response.Body.Description}} + {{- end}} + std::stringstream body; + {{- else if eq $operation.Response.Body.Type "binary" -}} + {{- if $operation.Response.Body.Description -}} + // {{$operation.Response.Body.Description}} + {{- end}} + std::iostream body; + {{- end -}} +} + {{- else -}} +typedef class QSRequest {{$opID}}Result; + {{- end -}} +{{end}} + + +{{define "Type"}} + {{- $typeName := index . 0 -}} + {{- $disablePointer := index . 1 -}} + + {{- if eq $typeName "string" -}} + std::string{{" " -}} + {{- else if eq $typeName "boolean" -}} + bool{{" " -}} + {{- else if eq $typeName "long" -}} + int64_t{{" " -}} + {{- else if eq $typeName "integer" -}} + int{{" " -}} + {{- else if eq $typeName "timestamp" -}} + std::string{{" " -}} + {{- else if eq $typeName "binary" -}} + char{" " -}}* + {{- else if eq $typeName "array" -}} + std::vector<> + {{- else if eq $typeName "object" -}} + {{$typeName | camelCase}}Type{{" " -}} + {{- else if eq $typeName "map" -}} + interface{} + {{- else if eq $typeName "any" -}} + interface{} + {{- else -}} + {{$typeName | camelCase}}Type{{" " -}} + {{- end -}} +{{end}} + +{{define "PropertyType"}} + {{- $property := index . 0 -}} + {{- $disablePointer := index . 1 -}} + + {{- if eq $property.Type "object" -}} + {{template "Type" passThrough $property.ExtraType $disablePointer}} + {{- else if eq $property.Type "array" -}} + []{{template "Type" passThrough $property.ExtraType $disablePointer}} + {{- else if eq $property.Type "map" -}} + map[string]{{template "Type" passThrough $property.ExtraType $disablePointer}} + {{- else if eq $property.Type "any" -}} + {{template "Type" passThrough $property.Type $disablePointer}} + {{- else -}} + {{template "Type" passThrough $property.Type $disablePointer}} + {{- end -}} +{{end}} + +{{define "PropertyTags"}} + {{- $property := . -}} + {{- if $property.IsRequired -}} + {{- printf `json:"%s"` ($property.Name | normalized) -}} + {{- else -}} + {{- printf `json:"%s,omitempty"` ($property.Name | normalized) -}} + {{- end -}} + {{- printf ` name:"%s"` ($property.Name | normalized) -}} + {{- if $property.Format}} + {{- printf ` format:"%s"` $property.Format -}} + {{- end -}} + {{- if $property.Default -}} + {{- printf ` default:"%s"` $property.Default -}} + {{- end -}} +{{end}} + +{{define "PropertyExtraTags"}} + {{- $propertyExtraTags := . -}} + {{- if $propertyExtraTags -}} + {{- printf " %s" $propertyExtraTags -}} + {{- end -}} +{{end}} diff --git a/template/header/sub_service.tmpl b/template/header/sub_service.tmpl new file mode 100644 index 0000000..28b61e0 --- /dev/null +++ b/template/header/sub_service.tmpl @@ -0,0 +1,119 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +{{$service := .Data.Service}} +{{$subServices:= .Data.SubServices}} + +#pragma once + +#include +#include +#include +#include "QsSdkOption.h" +#include "Types.h" +#include "QsErrors.h" +#include "QsConfig.h" + +#ifdef BUILD_C_STYLE_INTERFACE +#include "service_with_c_style/QingStorCStyle.h" +#endif // BUILD_C_STYLE_INTERFACE + +#define BASIC_FLAG 0x0 + +{{- range $_, $operation := $service.Operations -}} + {{- $data := $operation.Request.Query -}} + {{- $arr1 :=converArray $data.Properties -}} + {{- $data := $operation.Request.Headers -}} + {{- $arr2 :=converArray $data.Properties -}} + {{- $data := $operation.Request.Elements -}} + {{- $arr3 :=converArray $data.Properties -}} + {{- $arr :=mergeArray $arr1 $arr2 -}} + {{- $arr :=mergeArray $arr $arr3 -}} + {{- template "RenderInputPropertiesFlags" passThrough $operation $arr -}} + + {{- $data := allRespnoseHeaders $operation.Responses -}} + {{- $arr1 := converArray $data -}} + {{- $data := allRespnoseElements $operation.Responses -}} + {{- $arr2 := converArray $data -}} + {{- $arr :=mergeArray $arr1 $arr2 -}} + {{- template "RenderOutputPropertiesFlags" passThrough $operation $arr -}} + +{{- end -}} +{{- range $_, $subService := $subServices -}} + {{- range $_, $operation := $subService.Operations}} + {{- $data := $operation.Request.Query -}} + {{- $arr1 :=converArray $data.Properties -}} + {{- $data := $operation.Request.Headers -}} + {{- $arr2 :=converArray $data.Properties -}} + {{- $data := $operation.Request.Elements -}} + {{- $arr3 :=converArray $data.Properties -}} + {{- $arr :=mergeArray $arr1 $arr2 -}} + {{- $arr :=mergeArray $arr $arr3 -}} + {{- template "RenderInputPropertiesFlags" passThrough $operation $arr -}} + + {{- $data := allRespnoseHeaders $operation.Responses -}} + {{- $arr1 := converArray $data -}} + {{- $data := allRespnoseElements $operation.Responses -}} + {{- $arr2 := converArray $data -}} + {{- $arr := mergeArray $arr1 $arr2 -}} + {{- template "RenderOutputPropertiesFlags" passThrough $operation $arr -}} + {{- end -}} +{{- end -}} + +namespace QingStor +{ +{{- range $_, $subService := $subServices}} +// +-------------------------------------------------------------------- +// | InputClassHeader +// +-------------------------------------------------------------------- + {{- range $_, $operation := $subService.Operations}} + {{template "InputClassHeader" passThrough $subService $operation}} + {{- end -}} +{{- end}} + +{{- range $_, $subService := $subServices}} +// +-------------------------------------------------------------------- +// | OutputClassHeader +// +-------------------------------------------------------------------- + {{- range $_, $operation := $subService.Operations}} + {{template "OutputClassHeader" passThrough $subService $operation}} + {{- end -}} +{{- end}} + +// +-------------------------------------------------------------------- +// | Bucket +// +-------------------------------------------------------------------- +class QS_SDK_API Bucket +{ + public: + Bucket(const QsConfig &qsConfig, const std::string &strBucketName, + const std::string &strZone); + + virtual ~Bucket(){}; + {{- range $_, $subService := $subServices}} + {{- range $_, $operation := $subService.Operations -}} + {{template "OperationDeclaration" passThrough $subService $operation}} + {{- end -}} + {{end}} + private: + QsConfig m_qsConfig; + Properties m_properties; + +}; + + +}// namespace QingStor + diff --git a/template/header/types.tmpl b/template/header/types.tmpl new file mode 100644 index 0000000..8e84f2e --- /dev/null +++ b/template/header/types.tmpl @@ -0,0 +1,135 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +{{- $service := .Data.Service -}} +{{- $objectSubService := index .Data.SubServices "Object" -}} +{{- $customizedTypes := .Data.CustomizedTypes}} + +#pragma once + +#include "QsSdkOption.h" +#include "QsErrors.h" +#include "HttpCommon.h" +#include +#include +#include +#include "types/ACLType.h" +#include "types/BucketType.h" +#include "types/ConditionType.h" +#include "types/CORSRuleType.h" +#include "types/GranteeType.h" +#include "types/IPAddressType.h" +#include "types/IsNullType.h" +#include "types/KeyType.h" +#include "types/KeyDeleteErrorType.h" +#include "types/NotIPAddressType.h" +#include "types/ObjectPartType.h" +#include "types/OwnerType.h" +#include "types/StatementType.h" +#include "types/StringLikeType.h" +#include "types/StringNotLikeType.h" +#include "types/UploadsType.h" + +namespace QingStor +{ + +struct ResponseErrorInfo +{ + std::string code; + std::string message; + std::string requestID; + std::string url; +}; + +typedef QsBaseType QsInput; + +class QS_SDK_API QsOutput:public QsBaseType +{ +public: + QsOutput():m_responseCode(Http::REQUEST_NOT_MADE) + { + }; + + QsOutput(QsError err, + Http:: + HttpResponseCode responseCode):m_responseCode(responseCode) + { + }; + + virtual ~ QsOutput() + { + }; + + virtual bool IsVaild() + { + return true; + }; + + inline std::string GetRequestID() const + { + return m_requestID; + }; + + inline Http::HttpResponseCode GetResponseCode() const + { + return m_responseCode; + }; + + inline ResponseErrorInfo GetResponseErrInfo() const + { + return m_errorInfo; + }; + + + inline void SetRequestID(const std::string & requestID) + { + m_requestID = requestID; + }; + + inline void SetResponseCode(Http::HttpResponseCode responseCode) + { + m_responseCode = responseCode; + }; + + inline void SetResponseErrInfo(const ResponseErrorInfo & errorInfo) + { + m_errorInfo = errorInfo; + }; + +protected: + std::string m_requestID; + + Http::HttpResponseCode m_responseCode; + + ResponseErrorInfo m_errorInfo; +}; + + +// Properties presents the service properties. +struct Properties{ + + // Bucket name + std::string BucketName; // Required + + // Object key + std::string ObjectKey; // Required + + // QingCloud Zone ID + std::string Zone; + +}; + +} // namespace QingStor + diff --git a/template/header/types_cpp.tmpl b/template/header/types_cpp.tmpl new file mode 100644 index 0000000..4f30878 --- /dev/null +++ b/template/header/types_cpp.tmpl @@ -0,0 +1,114 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +{{- $service := .Data.Service -}} +{{- $objectSubService := index .Data.SubServices "Object" -}} +{{- $customizedTypes := .Data.CustomizedTypes -}} +{{- $currentTypeID := .CurrentSubServiceID}} + +#pragma once + +#include "../QsBaseType.h" +#include + +// Headers of CustomizedType. +{{- range $_, $customizedType := $customizedTypes}} +{{- if eq $currentTypeID $customizedType.ID}} + {{- range $_, $property := $customizedType.Properties -}} + {{- range $_, $customizedType := $customizedTypes -}} + {{- if eq $property.ID $customizedType.ID}} +#include "{{$customizedType.ID | camelCase}}Type.h" + {{- end -}} + {{- end -}} + {{- end}} + +#ifdef BUILD_C_STYLE_INTERFACE +#include "../service_with_c_style/types/{{$customizedType.ID | camelCase}}Type.h" +#endif // BUILD_C_STYLE_INTERFACE + +{{$arr :=converArray $customizedType.Properties}} +{{- template "RenderPropertiesFlags" passThrough $customizedType $arr}} + +//{{$customizedType.ID | camelCase}}Type presents costom type:{{$customizedType.ID | camelCase}}. +class QS_SDK_API {{$customizedType.ID | camelCase}}Type: QsBaseType +{ + +public: + {{$customizedType.ID | camelCase}}Type(){}; + {{$customizedType.ID | camelCase}}Type(std::string serializedStr); + +#ifdef BUILD_C_STYLE_INTERFACE + {{$customizedType.ID | camelCase}}Type(qs_{{$customizedType.ID}}_t {{$customizedType.ID}}); + qs_{{$customizedType.ID}}_t * toCStyleObj(); +#endif // BUILD_C_STYLE_INTERFACE + + {{- range $_, $property := $customizedType.Properties -}} + {{- if $property.Description -}} + // {{$property.Description -}} + {{- end}} + {{- if $property.Enum}} + // {{$property.ID | camelCase}}'s available values: {{$property.Enum | commaConnected -}} + {{- end}} + + {{- $isString := eq $property.Type "string" -}} + {{- $isTimeStamp := eq $property.Type "timestamp" -}} + + {{- if eq $property.Type "integer"}} + {{else if eq $property.Type "array"}} +#ifdef BUILD_C_STYLE_INTERFACE + inline void Set{{$property.ID | camelCase}}({{template "CStylePropertyType" passThrough $property false}} {{" " -}} {{$property.ID | snakeCase}}) + { + m_settingFlag |= SETTING_{{$customizedType.ID | snakeCase |upper}}_{{$property.ID | snakeCase |upper}}_FLAG; + + {{if eq $property.Type "array"}} + qs_{{$property.ExtraType | snakeCase}}_item_t * item; + + qs_list_for_each_entry(qs_{{$property.ExtraType | snakeCase}}_item_t, item, {{$property.ID | snakeCase}}) + { + {{- if eq $property.ExtraType "string"}} + m_{{$property.ID | camelCase | upperFirst}}.push_back(item->content); + {{- else -}} + m_{{$property.ID | camelCase | upperFirst}}.push_back(*item->content); + {{- end}} + } + {{- else}} + m_{{$property.ID | camelCase | upperFirst}} = {{$property.ID | snakeCase}}; + {{end}} + + }; +#endif // BUILD_C_STYLE_INTERFACE + {{else}} + {{- end}} + + inline void Set{{$property.ID | camelCase}}({{template "RequestPropertyType" passThrough $property false}}{{" " -}} {{$property.ID | camelCase}}) + { + m_settingFlag |= SETTING_{{$customizedType.ID | snakeCase |upper}}_{{$property.ID | snakeCase |upper}}_FLAG; + m_{{$property.ID | camelCase | upperFirst}} = {{$property.ID | camelCase}}; + }; + + inline{{" "}}{{- template "RequestPropertyType" passThrough $property false}} Get{{$property.ID | camelCase}}(){return m_{{$property.ID | camelCase | upperFirst}};}; + + {{end -}} + + std::string Serialize(); + +private: + {{template "RenderProperties" passThrough $customizedType "" ""}} + + int setting_flag; +}; +{{- end -}} +{{end}} + diff --git a/template/header_with_c_style/manifest.json b/template/header_with_c_style/manifest.json new file mode 100644 index 0000000..1c091a6 --- /dev/null +++ b/template/header_with_c_style/manifest.json @@ -0,0 +1,42 @@ +{ + + "output": { + "file_naming": { + "style": "camel_case", + "extension": ".h" + } + }, + "template_files": { + "shared": { + "file_path": "shared.tmpl" + }, + "service": { + "file_path": "service.tmpl", + "output_file_naming": { + "prefix": "", + "suffix": "" + } + }, + "sub_service": { + "file_path": "sub_service.tmpl", + "output_file_naming": { + "prefix": "", + "suffix": "" + } + }, + "types": { + "file_path": "types.tmpl", + "output_file_naming": { + "prefix": "", + "suffix": "" + } + }, + "types_cpp": { + "file_path": "types_cpp.tmpl", + "output_file_naming": { + "prefix": "", + "suffix": "Type" + } + } + } +} diff --git a/template/header_with_c_style/service.tmpl b/template/header_with_c_style/service.tmpl new file mode 100644 index 0000000..2a2ee18 --- /dev/null +++ b/template/header_with_c_style/service.tmpl @@ -0,0 +1,108 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +{{$service := .Data.Service}} +{{$className := $service.Name}} +{{$subServices:= .Data.SubServices}} +#pragma once + +#include "../QsSdkOption.h" +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + void * pQsService; + void * pQsBucket; +} qs_context_handle; + +typedef struct +{ + const char * additional_user_agent; + const char * access_key_id; + const char * secret_access_key; + const char * host; + const char * protocol; + int port; + int conn_retries; + int timeout_period; +} qs_config_t; + +// "init_and_cleanup_curl": SDK wide options for curl +// If it is being used then we automatically initialize and clean it up. +// If this is a problem for you, set this to false. +QS_SDK_API void qs_init_sdk(const char *logfile_path, LogLevel qs_log_level, + unsigned int init_and_cleanup_curl); + +QS_SDK_API void qs_shutdown_sdk(unsigned int init_and_cleanup_curl); + +// Create service and get contex handle which is used with erery SDK API. +QS_SDK_API qs_context_handle qs_create_service(qs_config_t qs_config, + const char *qs_bucket_name, + const char *qs_bucket_zone); + +// Same to fuction "qs_create_service".Specify the path to config file +// instead of providing config structure. +QS_SDK_API qs_context_handle qs_create_service_with_configfile(const char + *qs_config_path, + const char + *qs_bucket_name, + const char + *qs_bucket_zone); + +// Release contex handle created by functuin "qs_create_service". +QS_SDK_API void qs_release_service(qs_context_handle context_hdl); + + {{- range $_, $operation := $service.Operations}} + {{template "InputCStyleHeader" passThrough $service $operation}} + {{template "InputCStyleInitDeclaration" passThrough $service $operation}} + {{- end -}} + + {{- range $_, $subService := $subServices}} + {{- range $_, $operation := $subService.Operations}} + {{template "InputCStyleHeader" passThrough $subService $operation}} + {{template "InputCStyleInitDeclaration" passThrough $subService $operation}} + {{- end -}} + {{- end -}} + + {{- range $_, $operation := $service.Operations}} + {{template "OutputCStyleHeader" passThrough $service $operation}} + {{template "OutputCStyleReleaseDeclaration" passThrough $service $operation}} + {{- end -}} + + {{- range $_, $subService := $subServices}} + {{- range $_, $operation := $subService.Operations}} + {{template "OutputCStyleHeader" passThrough $subService $operation}} + {{template "OutputCStyleReleaseDeclaration" passThrough $subService $operation}} + {{- end -}} + {{- end -}} + + + {{range $_, $operation := $service.Operations -}} + {{template "OperationDeclaration" passThrough $service $operation}} + {{end}} + + {{- range $_, $subService := $subServices}} + {{range $_, $operation := $subService.Operations -}} + {{template "OperationDeclaration" passThrough $subService $operation}} + {{end}} + {{end}} + +#ifdef __cplusplus +} +#endif diff --git a/template/header_with_c_style/shared.tmpl b/template/header_with_c_style/shared.tmpl new file mode 100644 index 0000000..66dba3b --- /dev/null +++ b/template/header_with_c_style/shared.tmpl @@ -0,0 +1,265 @@ + + +{{define "OperationDeclaration"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | snakeCase -}} + {{- $belongs := replace $service.Name "QingStor" "Service" -1 -}} + {{- $belongs := replace $belongs "Object" "Bucket" -1 -}} + {{- $isBucket := eq $service.Name "Bucket" -}} + {{- $isObject := eq $service.Name "Object" -}} + + {{if $operation.Description -}} + {{if eq $belongs "Bucket" -}} +// {{replace $opID "Bucket" "" -1}} does {{$operation.Description -}} + {{else -}} +// {{$opID}} does {{$operation.Description -}} + {{end -}} + {{- end}} + {{- if $operation.DocumentationURL }} +// Documentation URL: {{$operation.DocumentationURL}} + {{- end}} +QsError QS_SDK_API qs_{{$opID}}({{- if $isObject}}char* objectKey, {{end -}}qs_{{$opID}}_input_t* input, qs_{{$opID}}_output_t* output, qs_context_handle context_hdl); +{{end}} + + +{{define "InputCStyleInitDeclaration"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | snakeCase -}} +// {{$opID}}Input init function. +void init_{{$opID}}_input(qs_{{$opID}}_input_t * input); +{{- end -}} + + +{{define "InputCStyleHeader"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | snakeCase -}} + {{- $belongs := replace $service.Name "QingStor" "Service" -1 -}} + {{- $belongs := replace $belongs "Object" "Bucket" -1}} + {{- $uri := $operation.Request.Path}} + {{- $uri := replace $uri "{" "<" -1}} + {{- $uri := replace $uri "}" ">" -1}} + {{- $uri := dashConnected $uri}} + {{- $hasHeaders := gt (len $operation.Request.Headers.Properties) 0 -}} + {{- $hasElements := gt (len $operation.Request.Elements.Properties) 0 -}} + {{- $hasParams := gt (len $operation.Request.Query.Properties) 0 -}} + {{- $hasStringBody := eq $operation.Request.Body.Type "string" -}} + {{- $hasBinaryBody := eq $operation.Request.Body.Type "binary" -}} + {{- $hasInput := or $hasHeaders $hasElements $hasParams $hasStringBody $hasBinaryBody -}} + +{{- if $hasInput}} +// {{$opID}}Input presents input for {{$opID}}. +typedef struct { + {{- if $hasParams}} + {{- $data := $operation.Request.Query.Properties -}} + {{template "RenderCStyleProperties" passThrough $data `location:"params"` $operation.Name}} + {{- end -}} + {{- if $hasHeaders}} + {{- $data := $operation.Request.Headers.Properties -}} + {{template "RenderCStyleProperties" passThrough $data `location:"headers"` $operation.Name}} + {{- end -}} + {{- if $hasElements}} + {{- $data := $operation.Request.Elements.Properties -}} + {{template "RenderCStyleProperties" passThrough $data `location:"elements"` $operation.Name}} + {{- end -}} + {{- if $hasBinaryBody}} + int64_t * bufLength; + + void* bodybuf; + {{end}} +} qs_{{$opID}}_input_t; +{{else}} +typedef qs_default_input_s qs_{{$opID}}_input_t; +{{- end -}} +{{- end -}} + +{{define "OutputCStyleReleaseDeclaration"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | snakeCase}} +// {{$opID}}Input init function. +void release_{{$opID}}_output(qs_{{$opID}}_output_t * output); +{{- end -}} + +{{define "OutputCStyleHeader"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | snakeCase -}} + {{- $belongs := replace $service.Name "QingStor" "Service" -1 -}} + {{- $belongs := replace $belongs "Object" "Bucket" -1}} + {{- $hasRespHeaders := gt (len (allRespnoseHeaders $operation.Responses)) 0 -}} + {{- $hasRespElements := gt (len (allRespnoseElements $operation.Responses)) 0 -}} + {{- $responseBody := getRespnosesBody $operation.Responses -}} + {{- $hasRespStringBody := eq $responseBody.Type "string" -}} + {{- $hasRespBinaryBody := eq $responseBody.Type "binary" -}} + {{- $hasOutput := or $hasRespHeaders $hasRespElements $hasRespStringBody $hasRespBinaryBody}} + +{{- if $hasOutput}} +typedef struct { + + {{- $data := allRespnoseHeaders $operation.Responses -}} + {{template "RenderCStyleProperties" passThrough $data `location:"headers"` $operation.Name}} + + {{- $data := allRespnoseElements $operation.Responses -}} + {{template "RenderCStyleProperties" passThrough $data `location:"elements"` $operation.Name}} + + {{- range $keyStatus, $valueStatus := $operation.Responses -}} + {{- if eq $valueStatus.Body.Type "binary"}} + {{- if $valueStatus.Body.Description -}} + // {{$valueStatus.Body.Description}} + {{- end}} + + int64_t * bufLength; + + void* bodybuf; + {{- end}} + {{- end}} + + int response_code; + + qs_error_info_t error_info; + +} qs_{{$opID}}_output_t; +{{else}} +typedef qs_default_output_s qs_{{$opID}}_output_t; +{{- end -}} +{{- end -}} + +{{define "RenderCStyleListItemStruct"}} + {{- $customizedType := index . 0 -}} + {{- $propertyExtraTags := index . 1 -}} + {{- $operationName := index . 2 -}} +typedef struct { + + qs_list_t node; + + qs_{{$customizedType.ID}}_t * content; + +}qs_{{$customizedType.ID | snakeCase}}_item_t; + + {{range $_, $property := $customizedType.Properties -}} + {{- $isTypeArray := eq $property.Type "array" -}} + {{- $isExtraTypeString := eq $property.ExtraType "string" -}} +{{- if $isTypeArray -}} +typedef struct{ + qs_list_t node; + + {{template "TypeWithCStyle" passThrough $property.ExtraType ""}}{{" " -}}content; + +} qs_{{$customizedType.ID | snakeCase}}_{{$property.ID | snakeCase}}_item_t; +{{- end}} + {{end}} + +{{end}} + +{{define "RenderCStyleProperties"}} + {{- $properties := index . 0 -}} + {{- $propertyExtraTags := index . 1 -}} + {{- $operationName := index . 2 -}} + + {{- range $_, $property := $properties -}} + {{- if $property.Description}} + // {{- $property.Description -}} + {{- end}} + {{- if $property.Enum -}} + // {{- $property.ID | snakeCase}}'s available values: {{$property.Enum | commaConnected -}} + {{- end}} + {{- if eq $property.Type "binary" -}} + + {{- else}} + {{template "CStylePropertyType" passThrough $property false}}{{" " -}}{{$property.ID | snakeCase}}; + {{- end}} + {{- if $property.IsRequired -}} + // Required + {{- end -}} + {{- end -}} +{{end}} + + +{{define "CStylePropertyType"}} + {{- $property := index . 0 -}} + {{- $disablePointer := index . 1 -}} + + {{- if eq $property.Type "object"}} + {{template "TypeWithCStyle" passThrough $property.ExtraType $disablePointer}} + {{- else if eq $property.Type "array"}} + qs_list_t * + {{- else if eq $property.Type "map"}} + // "C wit map??????????????????????" + {{- else if eq $property.Type "any"}} + {{template "TypeWithCStyle" passThrough $property.Type $disablePointer}} + {{- else -}} + {{template "TypeWithCStyle" passThrough $property.Type $disablePointer}} + {{- end -}} +{{end}} + +{{define "TypeWithCStyle"}} + {{- $typeName := index . 0 -}} + {{- $disablePointer := index . 1 -}} + + {{- if eq $typeName "string" -}} + char * {{" " -}} + {{- else if eq $typeName "boolean" -}} + int * {{" " -}} + {{- else if eq $typeName "integer" -}} + int *{{" " -}} + {{- else if eq $typeName "long" -}} + long *{{" " -}} + {{- else if eq $typeName "timestamp" -}} + char * {{" " -}} + {{- else if eq $typeName "binary" -}} + void *{" " -}} + {{- else if eq $typeName "array" -}} + qs_list_t * + {{- else if eq $typeName "object" -}} + interface{} + {{- else if eq $typeName "map" -}} + interface{} + {{- else if eq $typeName "any" -}} + interface{} + {{- else -}} + qs_{{$typeName}}_t *{{" " -}} + {{- end -}} +{{end}} + +{{define "PropertyType"}} + {{- $property := index . 0 -}} + {{- $disablePointer := index . 1 -}} + + {{- if eq $property.Type "object" -}} + {{template "TypeWithCStyle" passThrough $property.ExtraType $disablePointer}} + {{- else if eq $property.Type "array" -}} + []{{template "TypeWithCStyle" passThrough $property.ExtraType $disablePointer}} + {{- else if eq $property.Type "map" -}} + map[string]{{template "TypeWithCStyle" passThrough $property.ExtraType $disablePointer}} + {{- else if eq $property.Type "any" -}} + {{template "TypeWithCStyle" passThrough $property.Type $disablePointer}} + {{- else -}} + {{template "TypeWithCStyle" passThrough $property.Type $disablePointer}} + {{- end -}} +{{end}} + +{{define "PropertyTags"}} + {{- $property := . -}} + {{- if $property.IsRequired -}} + {{- printf `json:"%s"` ($property.Name | normalized) -}} + {{- else -}} + {{- printf `json:"%s,omitempty"` ($property.Name | normalized) -}} + {{- end -}} + {{- printf ` name:"%s"` ($property.Name | normalized) -}} + {{- if $property.Format}} + {{- printf ` format:"%s"` $property.Format -}} + {{- end -}} + {{- if $property.Default -}} + {{- printf ` default:"%s"` $property.Default -}} + {{- end -}} +{{end}} + +{{define "PropertyExtraTags"}} + {{- $propertyExtraTags := . -}} + {{- if $propertyExtraTags -}} + {{- printf " %s" $propertyExtraTags -}} + {{- end -}} +{{end}} \ No newline at end of file diff --git a/template/header_with_c_style/types.tmpl b/template/header_with_c_style/types.tmpl new file mode 100644 index 0000000..45b194c --- /dev/null +++ b/template/header_with_c_style/types.tmpl @@ -0,0 +1,46 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +{{$service := .Data.Service}} +{{$objectSubService := index .Data.SubServices "Object"}} +{{$customizedTypes := .Data.CustomizedTypes}} +#pragma once + +#include "../QsSdkOption.h" +#include "../QsErrors.h" +{{range $_, $customizedType := $customizedTypes -}} +#include "types/{{$customizedType.ID | camelCase}}Type.h" +{{end}} + +typedef struct +{ + char *code; + char *message; + char *request_id; + char *url; +} qs_error_info_t; + +typedef struct +{ + int response_code; + qs_error_info_t error_info; + +} qs_default_output_s; + +typedef struct +{ + int response_code; +} qs_default_input_s; \ No newline at end of file diff --git a/template/header_with_c_style/types_cpp.tmpl b/template/header_with_c_style/types_cpp.tmpl new file mode 100644 index 0000000..b09b648 --- /dev/null +++ b/template/header_with_c_style/types_cpp.tmpl @@ -0,0 +1,58 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +{{- $service := .Data.Service}} +{{- $objectSubService := index .Data.SubServices "Object"}} +{{- $customizedTypes := .Data.CustomizedTypes}} +{{- $currentTypeID := .CurrentSubServiceID}} +#pragma once + +#include "../QsList.h" +// Headers of CustomizedType. +{{- range $_, $customizedType := $customizedTypes}} +{{- if eq $currentTypeID $customizedType.ID}} + {{- range $_, $property := $customizedType.Properties -}} + {{- range $_, $customizedType := $customizedTypes -}} + {{- if eq $property.ID $customizedType.ID}} +#include "{{$customizedType.ID | camelCase}}Type.h" + {{- end -}} + {{- end -}} + {{- end}} +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + {{template "RenderCStyleProperties" passThrough $customizedType.Properties "" ""}} + + int setting_flag; +} qs_{{$customizedType.ID}}_t; + +{{template "RenderCStyleListItemStruct" passThrough $customizedType "" ""}} + +// {{$customizedType.ID}} init function. +void init_{{$customizedType.ID}}(qs_{{$customizedType.ID}}_t * input); + +// {{$customizedType.ID}} release function. +void release_{{$customizedType.ID}}(qs_{{$customizedType.ID}}_t * output); + + +{{- end -}} +{{- end}} + +#ifdef __cplusplus +}; +#endif \ No newline at end of file diff --git a/template/source/manifest.json b/template/source/manifest.json new file mode 100644 index 0000000..9301f2b --- /dev/null +++ b/template/source/manifest.json @@ -0,0 +1,10 @@ +{ + + "output": { + "file_naming": { + "style": "camel_case", + "extension": ".cpp" + } + } + +} diff --git a/template/source/service.tmpl b/template/source/service.tmpl new file mode 100644 index 0000000..9a3a48e --- /dev/null +++ b/template/source/service.tmpl @@ -0,0 +1,80 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +{{- $service := .Data.Service -}} +{{- $className := $service.Name}} +{{- $customizedTypes := .Data.CustomizedTypes}} + + +#include "QingStor.h" +#include "Bucket.h" +#include "QsConfig.h" +#include "request/QsRequest.h" +#include "http/HttpResponse.h" +#include "external/plog/Log.h" +#include "external/json/json.h" + +using namespace QingStor; + +void QingStor::InitializeSDK(const SDKOptions & options) +{ + //Init log systom + LOG_DEBUG << "Initializing SDK..."; + std::string logName = options.logPath; + logName += "qingstor_sdk_log.txt"; + plog::init((plog::Severity) options.logLevel, logName.c_str(), 1000000, 5); + if (options.initAndCleanupCurl) + { + //InitHttp + curl_global_init(CURL_GLOBAL_ALL); + LOG_DEBUG << "curl_global_init done"; + } + + HttpClient::CreateGlobaleCurlPool(); +} + +void QingStor::ShutdownSDK(const SDKOptions & options) +{ + LOG_DEBUG << "Shutdowning SDK..."; + if (options.initAndCleanupCurl) + { + //InitHttp + curl_global_cleanup(); + LOG_DEBUG << "curl_global_cleanup done"; + } + + HttpClient::DestroyGlobaleCurlPool(); +} + +QingStorService::QingStorService(const QsConfig &qsConfig) : m_qsConfig(qsConfig) +{ +} + +// +-------------------------------------------------------------------- +// | RequestBuilderSource and ResponseUnparkerSource +// +-------------------------------------------------------------------- +{{range $_, $operation := $service.Operations -}} +{{template "RequestBuilderSource" passThrough $service $operation $customizedTypes}} +{{template "ResponseUnparkerSource" passThrough $service $operation $customizedTypes}} +{{end}} + +// +-------------------------------------------------------------------- +// | SDK API Operation Source +// +-------------------------------------------------------------------- +{{range $_, $operation := $service.Operations -}} +{{template "OperationSource" passThrough $service $operation}} +{{end}} + + diff --git a/template/source/shared.tmpl b/template/source/shared.tmpl new file mode 100644 index 0000000..49d7375 --- /dev/null +++ b/template/source/shared.tmpl @@ -0,0 +1,454 @@ +{{define "TypeWithCStyle"}} + {{- $typeName := index . 0 -}} + {{- $disablePointer := index . 1 -}} + + {{- if eq $typeName "string" -}} + char{{" " -}} + {{- else if eq $typeName "boolean" -}} + int {{" " -}} + {{- else if eq $typeName "integer" -}} + int {{" " -}} + {{- else if eq $typeName "long" -}} + long {{" " -}} + {{- else if eq $typeName "timestamp" -}} + char{{" " -}} + {{- else if eq $typeName "binary" -}} + void {" " -}} + {{- else if eq $typeName "array" -}} + qs_list_t + {{- else if eq $typeName "object" -}} + interface{} + {{- else if eq $typeName "map" -}} + interface{} + {{- else if eq $typeName "any" -}} + interface{} + {{- else -}} + qs_{{$typeName}}_t{{" " -}} + {{- end -}} +{{end}} + +{{define "OperationSource"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | camelCase -}} + {{- $belongs := replace $service.Name "QingStor" "Service" -1 -}} + {{- $belongs := replace $belongs "Object" "Bucket" -1}} + {{- $uri := $operation.Request.Path}} + {{- $uri := replace $uri "{" "<" -1}} + {{- $uri := replace $uri "}" ">" -1}} + {{- $uri := dashConnected $uri}} + {{- $isBucket := eq $service.Name "Bucket"}} + {{- $isObject := eq $service.Name "Object"}} + {{- $hasQuery := gt (len $operation.Request.Query.Properties) 0}} + {{- $hasHeaders := gt (len $operation.Request.Headers.Properties) 0}} + {{- $hasElements := gt (len $operation.Request.Elements.Properties) 0}} + {{- $hasStringBody := eq $operation.Request.Body.Type "string"}} + {{- $hasBinaryBody := eq $operation.Request.Body.Type "binary"}} + {{- $hasInput := or $hasQuery $hasHeaders $hasElements $hasStringBody $hasBinaryBody}} + {{- $operationName := $opID | camelCase}} + + +QsError {{if or $isObject $isBucket}}Bucket::{{- else -}}QingStorService::{{end -}}{{$operationName}}({{- if $isObject}}std::string objectKey, {{end -}}{{$operation.ID}}Input& input, {{$operation.ID}}Output& output) +{ + Properties properties(m_properties); + {{- if $isObject}} + properties.ObjectKey = objectKey; + {{end}} + + Operation operation(&m_qsConfig, properties, + "{{$operation.Name}}", + HTTP_{{$operation.Request.Method}}, + "{{$uri}}" + ); + + {{$operation.ID}}Builder bulider(&input); + {{$operation.ID}}Unparker unparker(&output); + + QsRequest request(operation, &bulider, &unparker); + + return request.GetResponse(); +} +{{end}} + +{{define "RequestBuilderSource"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | camelCase -}} + {{- $hasQuery := gt (len $operation.Request.Query.Properties) 0 -}} + {{- $hasHeaders := gt (len $operation.Request.Headers.Properties) 0 -}} + {{- $hasElements := gt (len $operation.Request.Elements.Properties) 0 -}} + {{- $hasStringBody := eq $operation.Request.Body.Type "string" -}} + {{- $hasBinaryBody := eq $operation.Request.Body.Type "binary" -}} + {{- $hasInput := or $hasQuery $hasHeaders $hasElements $hasStringBody $hasBinaryBody}} +{{- if $hasInput -}} +class {{$opID}}Builder : public QsDefaultRequestBuilder <{{$operation.ID}}Input> +{ +public: + {{$opID}}Builder({{$operation.ID}}Input* input) + :QsDefaultRequestBuilder<{{$operation.ID}}Input>(input){}; + + virtual ~{{$opID}}Builder(){}; + + virtual bool CkeckIfInputIsVaild() { return m_input->CheckIfInputIsVaild();}; + + {{- if $hasHeaders}} + virtual Http::HeaderValueCollection GetHeaderValueCollection(); + {{- end}} + {{- if $hasQuery}} + virtual Http::QueryParamCollection GetQueryParamCollection(); + {{- end}} + {{- if or $hasElements $hasBinaryBody}} + virtual std::iostream* GetRequestBody(); + {{- end}} +}; + + +{{- if $hasHeaders}} +// {{$opID}}Request GetRequestSpecificHeaders. +Http::HeaderValueCollection {{$opID}}Builder::GetHeaderValueCollection() +{ + //TO DO; + Http::HeaderValueCollection headers; + std::stringstream ss; + std::vector::iterator it; + {{range $_, $HeaderPropertie := $operation.Request.Headers.Properties}} + if(m_input->IsPropHasBeenSet(SETTING_INPUT_{{$operation.ID |snakeCase |upper}}_{{$HeaderPropertie.ID |snakeCase |upper}}_FLAG)) + { + ss << m_input->Get{{$HeaderPropertie.ID | camelCase}}(); + headers.insert(Http::HeaderValuePair("{{$HeaderPropertie.ID}}", ss.str())); + ss.str(""); + } + {{end -}} + + return headers; +} +{{- end -}} + +{{- if $hasQuery}} +// {{$opID}}Request AddQueryStringParameters. +Http::QueryParamCollection {{$opID}}Builder::GetQueryParamCollection() +{ + Http::QueryParamCollection queryParameters; + + std::stringstream ss; + std::vector::iterator it; + + {{range $_, $QueryPropertie := $operation.Request.Query.Properties}} + if(m_input->IsPropHasBeenSet(SETTING_INPUT_{{$operation.ID |snakeCase |upper}}_{{$QueryPropertie.ID |snakeCase |upper}}_FLAG)) + { + ss << m_input->Get{{$QueryPropertie.ID | camelCase}}(); + queryParameters.insert(Http::HeaderValuePair("{{$QueryPropertie.ID}}", ss.str())); + ss.str(""); + } + {{end -}} + + return queryParameters; +} +{{- end -}} + +{{- if or $hasElements $hasBinaryBody}} +// {{$opID}}Request GetRequestBody. +std::iostream* {{$opID}}Builder::GetRequestBody() +{ + {{- if $hasBinaryBody}} + return m_input->GetBody(); + {{- else if eq (len $operation.Request.Elements.Properties) 0 }} + m_bNeedReleaseBody = true; + rerutn new std::stringstream(""); + {{- else}} + //TO DO; + Json::FastWriter jsonWriter; + Json::Value jsonContent; + + {{range $_, $property := $operation.Request.Elements.Properties -}} + {{- $isStringExtraType := eq $property.ExtraType "string" -}} + {{- $isIntgerExtraType := eq $property.ExtraType "integer" -}} + + if(m_input->IsPropHasBeenSet(SETTING_INPUT_{{$operation.ID |snakeCase |upper}}_{{$property.ID |snakeCase |upper}}_FLAG)) + { + {{if eq $property.Type "array"}} + Json::Value array{{$property.ID | camelCase}}; + + std::vector<{{- template "Type" passThrough $property.ExtraType true}}> {{$property.ID | camelCase| lowerFirstWord}} = m_input->Get{{$property.ID | camelCase}}(); + for(std::vector<{{- template "Type" passThrough $property.ExtraType true}}>::iterator it = {{$property.ID | camelCase| lowerFirstWord}}.begin(); it != {{$property.ID | camelCase| lowerFirstWord}}.end(); it++) + { + {{if or $isIntgerExtraType $isStringExtraType}} + array{{$property.ID | camelCase}}.append({{$property.ID | camelCase | lowerFirstWord}}Item); + {{else}} + Json::Reader jsonReader; + Json::Value itemJsonValue; + jsonReader.parse(it->Serialize(), itemJsonValue); + array{{$property.ID | camelCase}}.append(itemJsonValue); + {{end}} + } + jsonContent["{{$property.ID}}"] = array{{$property.ID | camelCase}}; + {{- else -}} + {{- if eq $property.Type "object"}} + jsonContent["{{$property.ID}}"] = m_input->Get{{$property.ID | camelCase}}().Serialize(); + {{- else if eq $property.Type "timestamp"}} + jsonContent["{{$property.ID}}"] = ctime(&m_{{$property.ID | camelCase}}); + {{- else}} + jsonContent["{{$property.ID}}"] = m_input->Get{{$property.ID | camelCase}}(); + {{- end}} + {{end}} + } + + {{end}} + m_bNeedReleaseBody = true; + return new std::stringstream(jsonWriter.write(jsonContent)); + {{end}} +} +{{- end -}} +{{- else -}} +typedef QsDefaultRequestBuilder<{{$operation.ID}}Input> {{$opID}}Builder; +{{end}} +{{end}} + + +{{define "ResponseUnparkerSource"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | camelCase -}} + {{- $hasRespHeaders := gt (len (allRespnoseHeaders $operation.Responses)) 0 -}} + {{- $hasRespElements := gt (len (allRespnoseElements $operation.Responses)) 0 -}} + {{- $responseBody := getRespnosesBody $operation.Responses -}} + {{- $hasRespStringBody := eq $responseBody.Type "string" -}} + {{- $hasRespBinaryBody := eq $responseBody.Type "binary" -}} + {{- $hasOutput := or $hasRespHeaders $hasRespElements $hasRespStringBody $hasRespBinaryBody}} + +{{- if $hasOutput -}} +class {{$opID}}Unparker : public QsDefaultResponseUnparker <{{$operation.ID}}Output> +{ +public: + {{$opID}}Unparker({{$operation.ID}}Output* output) + :QsDefaultResponseUnparker <{{$operation.ID}}Output> (output){}; + + virtual ~{{$opID}}Unparker(){}; + + virtual bool CkeckIfOutputIsVaild() { return m_output->IsVaild();}; + + virtual bool CheckIfResponseExpected(Http::HttpResponseCode responseCode) { + m_output->SetResponseCode(responseCode); + + // Expected response codes. + {{$numOfCode := len ($operation.Responses)}} + int expectedRespCode[{{$numOfCode}}] = + { + {{- range $StatusCode, $valueStatus := $operation.Responses -}} + {{$StatusCode}}, + {{- end -}} + }; + + bool isExpected = false; + for(int i = 0; i < {{$numOfCode}}; i++) + { + if(expectedRespCode[i] == responseCode){ + isExpected = true; + break; + } + } + + return isExpected; + }; + + {{- if $hasRespHeaders}} + virtual void ParseResponseHeaders(const Http::HeaderValueCollection & headerValueCollection); + {{- end}} + {{- if or $hasRespElements}} + virtual void ParseResponseBody(std::iostream* responseBody); + {{- end}} + {{- range $keyStatus, $valueStatus := $operation.Responses -}} + {{- if eq $valueStatus.Body.Type "binary"}} + virtual void ParseResponseBody(std::iostream* responseBody); + {{end}} + {{- end}} +}; + +{{- if $hasRespHeaders}} +// {{$opID}}Request ParseResponseHeaders. +void {{$opID}}Unparker::ParseResponseHeaders(const Http::HeaderValueCollection & headerValueCollection) +{ + const HeaderValueCollection& headers = headerValueCollection; + {{- $allRespHeadersProperties := allRespnoseHeaders $operation.Responses}} + {{range $_, $respHeaderPropertie := $allRespHeadersProperties}} + {{- $respHeaderPropName := $respHeaderPropertie.ID | camelCase}} + HeaderValueCollection::const_iterator {{$respHeaderPropName}}Iter = headers.find("{{$respHeaderPropertie.ID | lower}}"); + if({{$respHeaderPropName}}Iter != headers.end()) + { + {{if eq $respHeaderPropertie.Type "string" -}} + m_output->Set{{$respHeaderPropName}}({{$respHeaderPropName}}Iter->second); + {{else if eq $respHeaderPropertie.Type "long" -}} + m_output->Set{{$respHeaderPropName}}( StringUtils::ConvertToInt64({{$respHeaderPropName}}Iter->second.c_str())); + {{- else -}} + m_output->Set{{$respHeaderPropName}}({{$respHeaderPropName}}Iter->second); + {{- end}} + } + {{end}} +} +{{- end -}} + +{{- if $hasRespElements -}} +void {{$opID}}Unparker::ParseResponseBody(std::iostream* responseBody) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + + jsonReader.parse(*responseBody, jsonContent); + {{- $allRespElementsProperties := allRespnoseElements $operation.Responses}} + {{range $_, $property := $allRespElementsProperties -}} + {{- $ElementName := $property.ID | camelCase}} + if(jsonContent.isMember("{{$property.ID | lower}}")) + { + {{- if eq $property.Type "array" -}} + {{- $isStringExtraType := eq $property.ExtraType "string" -}} + {{- $isIntegerExtraType := eq $property.ExtraType "integer" -}} + {{" "}}{{template "RequestPropertyType" passThrough $property false}} vec{{$ElementName}}; + + for (unsigned i = 0; i < jsonContent["{{$property.ID | lower}}"].size(); ++i) + { + {{if $isStringExtraType -}} + vec{{$ElementName}}.push_back(jsonContent["{{$property.ID | lower}}"][i].asString()); + {{- else if $isIntegerExtraType -}} + vec{{$ElementName}}.push_back(jsonContent["{{$property.ID | lower}}"][i].asInt()); + {{- else -}} + vec{{$ElementName}}.push_back(jsonContent["{{$property.ID | lower}}"][i].toStyledString()); + {{- end}} + } + + m_output->Set{{$ElementName}}(vec{{$ElementName}}); + {{- else if eq $property.Type "boolean"}} + m_output->Set{{$ElementName}}(jsonContent["{{$property.ID | lower}}"].asBool()); + {{- else if eq $property.Type "integer" }} + m_output->Set{{$ElementName}}(jsonContent["{{$property.ID | lower}}"].asInt()); + {{- else if eq $property.Type "timestamp"}} + m_output->Set{{$ElementName}}(jsonContent["{{$property.ID | lower}}"].asString()); + {{- else if eq $property.Type "string"}} + m_output->Set{{$ElementName}}(jsonContent["{{$property.ID | lower}}"].asString()); + {{- else if eq $property.Type "long"}} + m_output->Set{{$ElementName}}(jsonContent["{{$property.ID | lower}}"].asInt64()); + {{- else}} + m_output->Set{{$ElementName}}(jsonContent["{{$property.ID | lower}}"].toStyledString()); + {{- end}} + } + {{end}} + + m_bNeedReleaseBody = true; +} +{{- end -}} + +{{- range $keyStatus, $valueStatus := $operation.Responses -}} +{{- if eq $valueStatus.Body.Type "binary"}} +void {{$opID}}Unparker::ParseResponseBody(std::iostream* responseBody) +{ + m_output->SetBody(responseBody); +} +{{end}} +{{- end}} +{{- else -}} +typedef QsDefaultResponseUnparker<{{$operation.ID}}Output> {{$opID}}Unparker; +{{end}} +{{end}} + +{{define "RequestPropertyType"}} + {{- $property := index . 0 -}} + {{- $disablePointer := index . 1 -}} + + {{- if eq $property.Format "int64"}} + int64_t + {{- else if eq $property.Type "object"}} + {{- template "Type" passThrough $property.ExtraType $disablePointer}} + {{- else if eq $property.Type "array"}} + std::vector< {{template "Type" passThrough $property.ExtraType $disablePointer}}> + {{- else if eq $property.Type "map"}} + Map[string]{{template "Type" passThrough $property.ExtraType $disablePointer}} + {{- else if eq $property.Type "any"}} + {{template "Type" passThrough $property.Type $disablePointer}} + {{- else -}} + {{template "Type" passThrough $property.Type $disablePointer}} + {{- end -}} +{{end}} + +{{define "RenderTypeTransFuns"}} + {{- $property := index . 0 -}} + {{- $typeName := $property.Type -}} + + {{- if eq $typeName "boolean" -}} + StringUtils::ConvertToBool + {{- else if eq $typeName "integer" -}} + StringUtils::ConvertToInt32 + {{- else -}} + {{- end -}} +{{end}} + +{{define "Type"}} + {{- $typeName := index . 0 -}} + {{- $disablePointer := index . 1 -}} + + {{- if eq $typeName "string" -}} + std::string{{" " -}} + {{- else if eq $typeName "boolean" -}} + bool{{" " -}} + {{- else if eq $typeName "integer" -}} + int{{" " -}} + {{- else if eq $typeName "long" -}} + long {{" " -}} + {{- else if eq $typeName "timestamp" -}} + std::string{{" " -}} + {{- else if eq $typeName "binary" -}} + char{" " -}}* + {{- else if eq $typeName "array" -}} + std::vector<> + {{- else if eq $typeName "object" -}} + interface{} + {{- else if eq $typeName "map" -}} + interface{} + {{- else if eq $typeName "any" -}} + interface{} + {{- else -}} + {{$typeName | camelCase}}Type{{" " -}} + {{- end -}} +{{end}} + +{{define "PropertyType"}} + {{- $property := index . 0 -}} + {{- $disablePointer := index . 1 -}} + + {{- if eq $property.Format "int64"}} + int64_t + {{- else if eq $property.Type "object" -}} + {{template "Type" passThrough $property.ExtraType $disablePointer}} + {{- else if eq $property.Type "array" -}} + []{{template "Type" passThrough $property.ExtraType $disablePointer}} + {{- else if eq $property.Type "map" -}} + map[string]{{template "Type" passThrough $property.ExtraType $disablePointer}} + {{- else if eq $property.Type "any" -}} + {{template "Type" passThrough $property.Type $disablePointer}} + {{- else -}} + {{template "Type" passThrough $property.Type $disablePointer}} + {{- end -}} +{{end}} + +{{define "PropertyTags"}} + {{- $property := . -}} + {{- if $property.IsRequired -}} + {{- printf `json:"%s"` ($property.Name | normalized) -}} + {{- else -}} + {{- printf `json:"%s,omitempty"` ($property.Name | normalized) -}} + {{- end -}} + {{- printf ` name:"%s"` ($property.Name | normalized) -}} + {{- if $property.Format}} + {{- printf ` format:"%s"` $property.Format -}} + {{- end -}} + {{- if $property.Default -}} + {{- printf ` default:"%s"` $property.Default -}} + {{- end -}} +{{end}} + +{{define "PropertyExtraTags"}} + {{- $propertyExtraTags := . -}} + {{- if $propertyExtraTags -}} + {{- printf " %s" $propertyExtraTags -}} + {{- end -}} +{{end}} + diff --git a/template/source/sub_service.tmpl b/template/source/sub_service.tmpl new file mode 100644 index 0000000..a40a6c8 --- /dev/null +++ b/template/source/sub_service.tmpl @@ -0,0 +1,59 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +{{- $service := .Data.Service -}} +{{- $subServices := .Data.SubServices}} + +#include "Bucket.h" +#include "StringUtils.h" +#include "request/QsRequest.h" +#include "http/HttpResponse.h" +#include "external/json/json.h" +#include +#include + +using namespace QingStor; +using namespace QingStor::Utils; + +#ifdef _WIN32 +#define GetObject GetObject +#endif + +Bucket::Bucket(const QsConfig &qsConfig, const std::string &strBucketName, const std::string &strZone) : m_qsConfig(qsConfig) +{ + m_properties.BucketName = strBucketName; + m_properties.Zone = strZone; +} + +{{- range $_, $subService := $subServices}} +// +-------------------------------------------------------------------- +// | RequestBuilderSource and ResponseUnparkerSource +// +-------------------------------------------------------------------- +{{range $_, $operation := $subService.Operations -}} +{{template "RequestBuilderSource" passThrough $subService $operation}} +{{template "ResponseUnparkerSource" passThrough $subService $operation}} +{{end}} +{{end}} + +{{- range $_, $subService := $subServices}} +// +-------------------------------------------------------------------- +// | SDK API Operation Source +// +-------------------------------------------------------------------- +{{range $_, $operation := $subService.Operations -}} +{{template "OperationSource" passThrough $subService $operation}} +{{end}} +{{end}} + + diff --git a/template/source/types.tmpl b/template/source/types.tmpl new file mode 100644 index 0000000..f31a7e4 --- /dev/null +++ b/template/source/types.tmpl @@ -0,0 +1,208 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +{{- $service := .Data.Service}} +{{- $objectSubService := index .Data.SubServices "Object"}} +{{- $customizedTypes := .Data.CustomizedTypes}} +{{- $currentTypeID := .CurrentSubServiceID}} + +// Headers of CustomizedType. +#include "Types.h" +#include "external/json/json.h" +#include +#include +#include +#include +#include + +{{range $_, $customizedType := $customizedTypes -}} + +#ifdef BUILD_C_STYLE_INTERFACE +{{$customizedType.ID | camelCase}}Type::{{$customizedType.ID | camelCase}}Type(qs_{{$customizedType.ID}}_t {{$customizedType.ID}}) +{ + {{range $_, $property := $customizedType.Properties -}} + {{- $isStringPorp := eq $property.Type "string" -}} + {{- $isTimeStampPorp := eq $property.Type "timestamp" -}} + {{- $isArrayPorp := eq $property.Type "array" -}} + {{- if or $isStringPorp $isTimeStampPorp $isArrayPorp}} + if({{$customizedType.ID}}.{{$property.ID | snakeCase}}) + Set{{$property.ID | camelCase}}({{$customizedType.ID}}.{{$property.ID | snakeCase}}); + {{- else}} + if({{$customizedType.ID}}.{{$property.ID | snakeCase}}) + Set{{$property.ID | camelCase}}(*{{$customizedType.ID}}.{{$property.ID | snakeCase}}); + {{- end}} + {{end}} +} + + +qs_{{$customizedType.ID}}_t * {{$customizedType.ID | camelCase}}Type::toCStyleObj() +{ + qs_{{$customizedType.ID}}_t * {{$customizedType.ID}} = (qs_{{$customizedType.ID}}_t *)malloc(sizeof(qs_{{$customizedType.ID}}_t)); + + {{range $_, $property := $customizedType.Properties -}} + {{- $isStringPorp := eq $property.Type "string" -}} + {{- $isTimeStampPorp := eq $property.Type "timestamp" -}} + {{- $isIntgerProp := eq $property.Type "integer" -}} + {{- $isLongPorp := eq $property.Type "long" -}} + {{- $isBooleanPorp := eq $property.Type "boolean" -}} + + {{- if or $isStringPorp $isTimeStampPorp}} + int {{$property.ID | camelCase| lowerFirstWord}}Length = 0; + {{$property.ID | camelCase| lowerFirstWord}}Length = Get{{$property.ID | camelCase}}().length(); + if({{$property.ID | camelCase| lowerFirstWord}}Length > 0){ + {{$customizedType.ID}}->{{$property.ID | snakeCase}} = (char *)malloc({{$property.ID | camelCase| lowerFirstWord}}Length +1); + memset({{$customizedType.ID}}->{{$property.ID | snakeCase}}, 0, {{$property.ID | camelCase | lowerFirstWord}}Length +1); + strncpy({{$customizedType.ID}}->{{$property.ID | snakeCase}}, Get{{$property.ID | camelCase}}().c_str(), {{$property.ID | camelCase| lowerFirstWord}}Length); + }else{ + {{$customizedType.ID}}->{{$property.ID | snakeCase}} = NULL; + } + {{else if or $isIntgerProp $isLongPorp}} + {{$customizedType.ID}}->{{$property.ID | snakeCase}} = ({{template "TypeWithCStyle" passThrough $property.Type false}} *)malloc(sizeof({{template "TypeWithCStyle" passThrough $property.Type false}})); + *{{$customizedType.ID}}->{{$property.ID | snakeCase}} = Get{{$property.ID | camelCase}}(); + {{else if $isBooleanPorp}} + {{$customizedType.ID}}->{{$property.ID | snakeCase}} = ({{template "TypeWithCStyle" passThrough $property.Type false}} *)malloc(sizeof({{template "TypeWithCStyle" passThrough $property.Type false}})); + *{{$customizedType.ID}}->{{$property.ID | snakeCase}} = (int)Get{{$property.ID | camelCase}}(); + {{else if eq $property.Type "array"}} + + qs_list_t * list_{{$property.ID | snakeCase}} = (qs_list_t *)malloc(sizeof(qs_list_t)); + + qs_list_init(list_{{$property.ID | snakeCase}}); + + std::vector<{{template "Type" passThrough $property.ExtraType false}}> {{$property.ID | camelCase | lowerFirstWord}} = Get{{$property.ID | camelCase}}(); + + for(std::vector<{{- template "Type" passThrough $property.ExtraType true}}>::iterator it = {{$property.ID | camelCase| lowerFirstWord}}.begin(); it != {{$property.ID | camelCase| lowerFirstWord}}.end(); it++) + { + qs_{{$customizedType.ID | snakeCase}}_{{$property.ID | snakeCase}}_item_t * item = (qs_{{$customizedType.ID | snakeCase}}_{{$property.ID | snakeCase}}_item_t *)malloc(sizeof(qs_{{$customizedType.ID | snakeCase}}_{{$property.ID | snakeCase}}_item_t)); + + {{- if eq $property.ExtraType "string"}} + int {{$property.ID | camelCase | lowerFirstWord}}Length = it->length(); + if({{$property.ID | camelCase | lowerFirstWord }}Length > 0){ + item->content = (char *)malloc({{$property.ID | camelCase | lowerFirstWord}}Length +1); + memset(item->content, 0, {{$property.ID | camelCase | lowerFirstWord}}Length +1); + strncpy(item->content, it->c_str(), {{$property.ID | camelCase | lowerFirstWord}}Length); + }else{ + item->content = NULL; + } + {{- else if eq $property.ExtraType "integer"}} + *item = *it; + {{- else}} + item = it->toCStyleObj(); + {{end}} + qs_list_append(&item->node, list_{{$property.ID | snakeCase}}); + } + + {{$customizedType.ID}}->{{$property.Name | snakeCase}} = list_{{$property.ID | snakeCase}}; + + {{else}} + {{$customizedType.ID}}->{{$property.ID | snakeCase}} = Get{{$property.ID | camelCase}}().toCStyleObj(); + {{- end -}} + {{end}} + + return {{$customizedType.ID}}; +} + +#endif // BUILD_C_STYLE_INTERFACE + +{{$customizedType.ID | camelCase}}Type::{{$customizedType.ID | camelCase}}Type(std::string serializedString) +{ + // parse json content + Json::Reader jsonReader; + Json::Value jsonContent; + + jsonReader.parse(serializedString, jsonContent); + + {{range $_, $property := $customizedType.Properties -}} + {{- $ElementName := $property.ID | camelCase}} + if(jsonContent.isMember("{{$property.ID}}")) + { + {{if eq $property.Type "array"}} + {{- $isArryExtraType := eq $property.ExtraType "array" -}} + {{- $isObjectExtraType := eq $property.ExtraType "object" -}} + + {{if $isObjectExtraType}} + {{template "RequestPropertyType" passThrough $property false}} vec{{$ElementName}}; + {{else}} + {{template "RequestPropertyType" passThrough $property false}} vec{{$ElementName}}; + {{end}} + + for (unsigned i = 0; i < jsonContent["{{$property.ID}}"].size(); ++i) + { + vec{{$ElementName}}.push_back(jsonContent["{{$property.ID}}"][i].asString()); + } + + Set{{$ElementName}}(vec{{$ElementName}}); + {{else if eq $property.Type "boolean"}} + Set{{$ElementName}}(jsonContent["{{$property.ID}}"].asBool()); + {{else if eq $property.Type "long"}} + Set{{$ElementName}}(jsonContent["{{$property.ID}}"].asInt64()); + {{else if eq $property.Type "integer"}} + Set{{$ElementName}}(jsonContent["{{$property.ID}}"].asInt()); + {{else if eq $property.Type "timestamp"}} + Set{{$ElementName}}(jsonContent["{{$property.ID}}"].asString()); + {{else if eq $property.Type "string"}} + Set{{$ElementName}}(jsonContent["{{$property.ID}}"].asString()); + {{else}} + Set{{$ElementName}}(jsonContent["{{$property.ID}}"].toStyledString()); + {{- end}} + } + {{end}} + +} + +std::string {{$customizedType.ID | camelCase}}Type::Serialize() +{ + Json::Value jsonContent; + Json::FastWriter jsonWriter; + + {{range $_, $property := $customizedType.Properties -}} + if(m_settingFlag & SETTING_{{$customizedType.ID|snakeCase |upper }}_{{$property.ID|snakeCase |upper }}_FLAG) + { + {{if eq $property.Type "array"}} + Json::Value array{{$property.ID | camelCase}}; + + std::vector<{{- template "Type" passThrough $property.ExtraType true}}> {{$property.ID | camelCase| lowerFirstWord}} = m_{{$property.ID | camelCase}}; + for(std::vector<{{- template "Type" passThrough $property.ExtraType true}}>::iterator it = {{$property.ID | camelCase| lowerFirstWord}}.begin(); it != {{$property.ID | camelCase| lowerFirstWord}}.end(); it++) + { + {{if isCustomizedType $property $customizedTypes}} + Json::Reader jsonReader; + Json::Value itemJsonValue; + jsonReader.parse(it->Serialize(), itemJsonValue); + array{{$property.ID | camelCase}}.append(itemJsonValue); + {{- else -}} + array{{$property.ID | camelCase}}.append(*it); + {{end}} + } + jsonContent["{{$property.ID}}"] = array{{$property.ID | camelCase}}; + {{- else -}} + {{- if eq $property.Type "object"}} + Json::Reader jsonReader; + Json::Value itemJsonValue; + jsonReader.parse(m_{{$property.ID | camelCase}}.Serialize(), itemJsonValue); + jsonContent["{{$property.ID}}"] = itemJsonValue; + {{- else if eq $property.Type "timestamp"}} + jsonContent["{{$property.ID}}"] = m_{{$property.ID | camelCase}}; + {{- else if eq $property.Type "long"}} + jsonContent["{{$property.ID}}"] = (Json::Int64)m_{{$property.ID | camelCase}}; + {{- else}} + jsonContent["{{$property.ID}}"] = m_{{$property.ID | camelCase}}; + {{- end}} + {{end}} + } + + {{end}} + return jsonWriter.write(jsonContent); +} +{{end}} diff --git a/template/source_with_c_style/manifest.json b/template/source_with_c_style/manifest.json new file mode 100644 index 0000000..9301f2b --- /dev/null +++ b/template/source_with_c_style/manifest.json @@ -0,0 +1,10 @@ +{ + + "output": { + "file_naming": { + "style": "camel_case", + "extension": ".cpp" + } + } + +} diff --git a/template/source_with_c_style/service.tmpl b/template/source_with_c_style/service.tmpl new file mode 100644 index 0000000..c632ae8 --- /dev/null +++ b/template/source_with_c_style/service.tmpl @@ -0,0 +1,209 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2016 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- +{{- $service := .Data.Service -}} +{{- $className := $service.Name}} +{{$subServices:= .Data.SubServices}} + +#include "QingStor.h" +#include "Bucket.h" +#include "QsConfig.h" +#include "service_with_c_style/QingStorCStyle.h" +#include "utils/QsStream.h" +#include "external/plog/Log.h" + +using namespace QingStor; + +void qs_init_sdk(const char *logfile_path, LogLevel qs_log_level, + unsigned int init_and_cleanup_curl) +{ + QingStor::SDKOptions sdkOptions; + sdkOptions.logLevel = qs_log_level; + sdkOptions.logPath = logfile_path; + if(!init_and_cleanup_curl){ + sdkOptions.initAndCleanupCurl = false; + } + else{ + sdkOptions.initAndCleanupCurl = true; + } + + QingStor::InitializeSDK(sdkOptions); +} + +void qs_shutdown_sdk(unsigned int init_and_cleanup_curl) +{ + QingStor::SDKOptions sdkOptions; + if(!init_and_cleanup_curl){ + sdkOptions.initAndCleanupCurl = false; + } + else{ + sdkOptions.initAndCleanupCurl = true; + } + + QingStor::ShutdownSDK(sdkOptions); +} + +qs_context_handle qs_create_service_with_configfile(const char *qs_configfile, + const char *qs_bucket_name, + const char *qs_bucket_zone) +{ + qs_context_handle context_hdl; + QsConfig qsConfig; + qsConfig.LoadConfigFile(qs_configfile); + context_hdl.pQsService = new QingStorService(qsConfig); + context_hdl.pQsBucket = + new Bucket(qsConfig, qs_bucket_name, qs_bucket_zone); + return context_hdl; +} + +QS_SDK_API qs_context_handle qs_create_service(qs_config_t + qs_config, + const char + *qs_bucket_name, + const char *qs_bucket_zone) +{ + qs_context_handle context_hdl; + QsConfig qsConfig; + if (qs_config.additional_user_agent) + qsConfig.additionalUserAgent = qs_config.additional_user_agent; + if (qs_config.access_key_id) + qsConfig.accessKeyId = qs_config.access_key_id; + if (qs_config.secret_access_key) + qsConfig.secretAccessKey = qs_config.secret_access_key; + if (qs_config.host) + qsConfig.host = qs_config.host; + if (qs_config.protocol) + qsConfig.protocol = qs_config.protocol; + if(0 < qs_config.port && 65535 > qs_config.port) + { + qsConfig.port = qs_config.port; + } + + if(0 <= qs_config.conn_retries && 10 > qs_config.conn_retries) + { + qsConfig.connectionRetries = qs_config.conn_retries; + } + + if(0 <= qs_config.timeout_period && 100 > qs_config.timeout_period) + { + qsConfig.timeOutPeriod = qs_config.timeout_period; + } + + context_hdl.pQsService = new QingStorService(qsConfig); + context_hdl.pQsBucket = + new Bucket(qsConfig, qs_bucket_name, qs_bucket_zone); + return context_hdl; +} + +void qs_release_service(qs_context_handle context_hdl) +{ + if (context_hdl.pQsService) + { + QingStorService * pQsService2Delete = (QingStorService *)context_hdl.pQsService; + delete pQsService2Delete; + } + if (context_hdl.pQsBucket) + { + Bucket * pBucket2Delete = (Bucket *)context_hdl.pQsBucket; + delete pBucket2Delete; + } +} + +void qs_set_error_info(qs_error_info_t * err_info, ResponseErrorInfo & errInfo) +{ + int codeLength = errInfo.code.length(); + if (codeLength > 0) + { + err_info->code = (char *) malloc(codeLength + 1); + memset(err_info->code, 0, codeLength + 1); + strncpy(err_info->code, errInfo.code.c_str(), codeLength); + } + int messageLength = errInfo.message.length(); + if (messageLength > 0) + { + err_info->message = (char *) malloc(messageLength + 1); + memset(err_info->message, 0, messageLength + 1); + strncpy(err_info->message, errInfo.message.c_str(), messageLength); + } + int requestIDLength = errInfo.requestID.length(); + if (requestIDLength > 0) + { + err_info->request_id = (char *) malloc(requestIDLength + 1); + memset(err_info->request_id, 0, requestIDLength + 1); + strncpy(err_info->request_id, errInfo.requestID.c_str(), + requestIDLength); + } + int urlLength = errInfo.url.length(); + if (urlLength > 0) + { + err_info->url = (char *) malloc(urlLength + 1); + memset(err_info->url, 0, urlLength + 1); + strncpy(err_info->url, errInfo.url.c_str(), urlLength); + } +} + +void qs_release_error_info(qs_error_info_t * err_info) +{ + if (!err_info) + { + return; + } + + if(err_info->code) + { + free(err_info->code); + } + + if(err_info->message) + { + free(err_info->message); + } + + if(err_info->request_id) + { + free(err_info->request_id); + } + + if(err_info->url) + { + free(err_info->url); + } +} + +void qs_init_error_info(qs_error_info_t * err_info) +{ + err_info->code = NULL; + err_info->message = NULL; + err_info->request_id = NULL; + err_info->url = NULL; +} + +{{range $_, $operation := $service.Operations -}} +{{template "InputCStyleInitFun" passThrough $service $operation}} +{{template "OutputCStyleInitFun" passThrough $service $operation}} +{{template "OutputCStyleReleaseFun" passThrough $service $operation}} +{{template "OperationSourceWithCStyle" passThrough $service $operation}} +{{end}} + +{{- range $_, $subService := $subServices}} +{{- range $_, $operation := $subService.Operations}} + {{template "InputCStyleInitFun" passThrough $subService $operation}} + {{template "OutputCStyleInitFun" passThrough $subService $operation}} + {{template "OutputCStyleReleaseFun" passThrough $subService $operation}} + {{template "OperationSourceWithCStyle" passThrough $subService $operation}} +{{- end -}} +{{- end -}} + + diff --git a/template/source_with_c_style/shared.tmpl b/template/source_with_c_style/shared.tmpl new file mode 100644 index 0000000..c6a148b --- /dev/null +++ b/template/source_with_c_style/shared.tmpl @@ -0,0 +1,915 @@ +{{define "CustomTypeReleaseFun"}} + {{- $customizedType := index . 0 -}} + {{- $properties := $customizedType.Properties -}} +// {{$customizedType.ID}} release function. +void release_{{$customizedType.ID}}(qs_{{$customizedType.ID}}_t * content) +{ + {{- range $_, $property := $properties -}} + + {{- $isTypeArray := eq $property.Type "array" -}} + {{- $isTypeString := eq $property.Type "string" -}} + {{- $isTypeTimestamp := eq $property.Type "timestamp" -}} + {{- $isTypeInteger := eq $property.Type "integer" -}} + {{- $isTypeLong := eq $property.Type "long" -}} + {{- $isTypeBoolean := eq $property.Type "boolean" -}} + {{- $isTypeBinary := eq $property.Type "binary" -}} + + {{- if or $isTypeString $isTypeTimestamp $isTypeInteger $isTypeLong $isTypeBoolean $isTypeBinary}} + if(content->{{$property.ID | snakeCase}}){ + free(content->{{$property.ID | snakeCase}}); + } + {{- else if $isTypeArray}} + if(content->{{$property.ID | snakeCase}}){ + + qs_{{$property.ExtraType | snakeCase}}_item_t * item = NULL; + qs_{{$property.ExtraType | snakeCase}}_item_t * item_to_delete = NULL; + qs_list_for_each_entry(qs_{{$property.ExtraType | snakeCase}}_item_t, item, content->{{$property.ID | snakeCase}}) + { + {{- $isExtraTypeArray := eq $property.ExtraType "array" -}} + {{- $isExtraTypeString := eq $property.ExtraType "string" -}} + {{- $isExtraTypeTimestamp := eq $property.ExtraType "timestamp" -}} + {{- $isExtraTypeInteger := eq $property.ExtraType "integer" -}} + {{- $isExtraTypeLong := eq $property.ExtraType "long" -}} + {{- $isExtraTypeBoolean := eq $property.ExtraType "boolean" -}} + {{- $isExtraTypeBinary := eq $property.ExtraType "binary" -}} + + if(item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + + {{- if or $isExtraTypeString $isExtraTypeTimestamp $isExtraTypeInteger $isExtraTypeLong $isExtraTypeBoolean $isExtraTypeBinary -}} + free(item->content); + {{- else -}} + release_{{$property.ExtraType.ID}}(item->content); + free(item->content); + {{- end}} + } + + if(item_to_delete) + { + free(item_to_delete); + } + + free(content->{{$property.ID | snakeCase}}); + } + {{- else -}} + if(content->{{$property.ID| snakeCase}}){ + release_{{$property.ID}}(content->{{$property.ID| snakeCase}}); + free(content->{{$property.ID| snakeCase}}); + } + {{end}} + + {{- end -}} +} +{{- end -}} + +{{define "CustomTypeInitFun"}} + {{- $customizedType := index . 0 -}} + {{- $properties := $customizedType.Properties -}} +// {{$customizedType.ID}} init function. +void init_{{$customizedType.ID}}(qs_{{$customizedType.ID}}_t * content) +{ + {{- range $_, $property := $properties -}} + content->{{$property.ID | snakeCase}} = NULL; + {{- end -}} +} +{{- end -}} + +{{define "InputCStyleInitFun"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | snakeCase -}} + {{- $belongs := replace $service.Name "QingStor" "Service" -1 -}} + {{- $belongs := replace $belongs "Object" "Bucket" -1}} + {{- $hasHeaders := gt (len $operation.Request.Headers.Properties) 0 -}} + {{- $hasElements := gt (len $operation.Request.Elements.Properties) 0 -}} + {{- $hasParams := gt (len $operation.Request.Query.Properties) 0 -}} + {{- $hasStringBody := eq $operation.Request.Body.Type "string" -}} + {{- $hasBinaryBody := eq $operation.Request.Body.Type "binary" -}} + {{- $hasInput := or $hasHeaders $hasElements $hasParams $hasStringBody $hasBinaryBody}} +// {{$opID}}Input init function. +void init_{{$opID}}_input(qs_{{$opID}}_input_t * input) +{ +{{if $hasInput}} + {{- if $hasParams}} + {{- range $property := $operation.Request.Query.Properties}} + input->{{$property.ID | snakeCase}} = NULL; + {{- end -}} + {{- end -}} + {{- if $hasHeaders}} + {{- range $property := $operation.Request.Headers.Properties}} + input->{{$property.ID | snakeCase}} = NULL; + {{- end -}} + {{- end -}} + {{- if $hasElements}} + {{- range $property := $operation.Request.Elements.Properties}} + input->{{$property.ID | snakeCase}} = NULL; + {{- end -}} + {{- end -}} + {{- if $hasBinaryBody}} + input->bufLength = NULL; + + input->bodybuf = NULL; + {{- end -}} +{{- else}} + // nothing to do; +{{- end}} + return; +} +{{- end -}} + +{{define "OutputCStyleInitFun"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | snakeCase -}} +// {{$opID}}output init function. +void init_{{$opID}}_output(qs_{{$opID}}_output_t * output) +{ +{{- range $keyStatus, $valueStatus := $operation.Responses -}} + {{- $hasBinaryBody := eq $valueStatus.Body.Type "binary" -}} + {{- range $property := $valueStatus.Headers.Properties}} + output->{{$property.ID | snakeCase}} = NULL; + {{- end -}} + {{- range $property := $valueStatus.Elements.Properties}} + output->{{$property.ID | snakeCase}} = NULL; + {{- end -}} + {{- if $hasBinaryBody}} + output->bufLength = NULL; + + output->bodybuf = NULL; + {{- end -}} + qs_init_error_info(&output->error_info); +{{- end}} + return; +} +{{- end -}} + + +{{define "OutputCStyleReleaseFun"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | snakeCase -}} +// {{$opID}} Output release function. +void release_{{$opID}}_output(qs_{{$opID}}_output_t * output) +{ +{{- range $keyStatus, $valueStatus := $operation.Responses -}} + + {{- range $property := $valueStatus.Headers.Properties}} + {{- $isTypeArray := eq $property.Type "array" -}} + {{- $isTypeString := eq $property.Type "string" -}} + {{- $isTypeTimestamp := eq $property.Type "timestamp" -}} + {{- $isTypeInteger := eq $property.Type "integer" -}} + {{- $isTypeLong := eq $property.Type "long" -}} + {{- $isTypeBinary := eq $property.Type "binary" -}} + + {{- if or $isTypeString $isTypeTimestamp $isTypeInteger $isTypeLong $isTypeBinary}} + if(output->{{$property.ID | snakeCase}}){ + free(output->{{$property.ID | snakeCase}}); + } + {{- else if $isTypeArray}} + if(output->{{$property.ID | snakeCase}}){ + + qs_{{$property.ExtraType | snakeCase}}_item_t * item = NULL; + qs_{{$property.ExtraType | snakeCase}}_item_t * item_to_delete = NULL; + qs_list_for_each_entry(qs_{{$property.ExtraType | snakeCase}}_item_t, item, output->{{$property.ID | snakeCase}}) + { + {{- $isExtraTypeArray := eq $property.ExtraType "array" -}} + {{- $isExtraTypeString := eq $property.ExtraType "string" -}} + {{- $isExtraTypeTimestamp := eq $property.ExtraType "timestamp" -}} + {{- $isExtraTypeInteger := eq $property.ExtraType "integer" -}} + {{- $isExtraTypeLong := eq $property.ExtraType "long" -}} + {{- $isExtraTypeBinary := eq $property.ExtraType "binary" -}} + + if(item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + {{- if or $isExtraTypeString $isExtraTypeTimestamp $isExtraTypeInteger $isExtraTypeLong $isExtraTypeBinary -}} + free(item->content); + {{- else -}} + release_{{$property.ExtraType | snakeCase}}(item->content); + free(item->content); + {{- end}} + } + + if(item_to_delete) + { + free(item_to_delete); + } + + free(output->{{$property.ID | snakeCase}}); + } + {{- else -}} + if(output->{{$property.ID | snakeCase}}){ + release_{{$property.ID | snakeCase}}(output->{{$property.ID | snakeCase}}); + free(output->{{$property.ID | snakeCase}}); + } + {{end}} + {{- end -}} + + {{- range $property := $valueStatus.Elements.Properties}} + {{- $isTypeArray := eq $property.Type "array" -}} + {{- $isTypeString := eq $property.Type "string" -}} + {{- $isTypeTimestamp := eq $property.Type "timestamp" -}} + {{- $isTypeInteger := eq $property.Type "integer" -}} + {{- $isTypeLong := eq $property.Type "long" -}} + {{- $isTypeBinary := eq $property.Type "binary" -}} + + {{- if or $isTypeString $isTypeTimestamp $isTypeInteger $isTypeLong $isTypeBinary}} + if(output->{{$property.ID | snakeCase}}){ + + free(output->{{$property.ID | snakeCase}}); + } + {{- else if $isTypeArray}} + if(output->{{$property.ID | snakeCase}}){ + + qs_{{$property.ExtraType | snakeCase}}_item_t * item = NULL; + qs_{{$property.ExtraType | snakeCase}}_item_t * item_to_delete = NULL; + qs_list_for_each_entry(qs_{{$property.ExtraType | snakeCase}}_item_t, item, output->{{$property.ID | snakeCase}}) + { + {{- $isExtraTypeArray := eq $property.ExtraType "array" -}} + {{- $isExtraTypeString := eq $property.ExtraType "string" -}} + {{- $isExtraTypeTimestamp := eq $property.ExtraType "timestamp" -}} + {{- $isExtraTypeInteger := eq $property.ExtraType "integer" -}} + {{- $isExtraTypeLong := eq $property.ExtraType "long" -}} + {{- $isExtraTypeBinary := eq $property.ExtraType "binary" -}} + + if(item_to_delete) + { + free(item_to_delete); + } + item_to_delete = item; + + {{- if or $isExtraTypeString $isExtraTypeTimestamp $isExtraTypeInteger $isExtraTypeLong $isExtraTypeBinary -}} + free(item->content); + {{- else -}} + release_{{$property.ExtraType | snakeCase}}(item->content); + free(item->content); + {{- end}} + } + + if(item_to_delete) + { + free(item_to_delete); + } + + free(output->{{$property.ID | snakeCase}}); + } + {{- else -}} + if(output->{{$property.ID | snakeCase}}){ + release_{{$property.ID | snakeCase}}(output->{{$property.ID | snakeCase}}); + free(output->{{$property.ID | snakeCase}}); + } + {{end}} + {{- end -}} + + {{- if eq $valueStatus.Body.Type "binary"}} + // release binary body content + if(output->bodybuf) + { + free(output->bodybuf); + } + if(output->bufLength) + { + free(output->bufLength); + } + {{- end -}} +{{- end}} + + qs_release_error_info(&output->error_info); + + return; +} +{{- end -}} + +{{define "OperationSourceWithCStyle"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | camelCase -}} + {{- $belongs := replace $service.Name "QingStor" "Service" -1 -}} + {{- $belongs := replace $belongs "Object" "Bucket" -1}} + {{- $isBucket := eq $service.Name "Bucket"}} + {{- $isObject := eq $service.Name "Object"}} + {{- $hasParams := gt (len $operation.Request.Query.Properties) 0}} + {{- $hasHeaders := gt (len $operation.Request.Headers.Properties) 0}} + {{- $hasElements := gt (len $operation.Request.Elements.Properties) 0}} + {{- $hasStringBody := eq $operation.Request.Body.Type "string"}} + {{- $hasBinaryBody := eq $operation.Request.Body.Type "binary"}} + {{- $hasRespHeaders := gt (len (allRespnoseHeaders $operation.Responses)) 0 -}} + {{- $hasRespElements := gt (len (allRespnoseElements $operation.Responses)) 0 -}} + {{- $responseBody := getRespnosesBody $operation.Responses -}} + {{- $hasRespStringBody := eq $responseBody.Type "string" -}} + {{- $hasRespBinaryBody := eq $responseBody.Type "binary" -}} + {{- $hasOutput := or $hasRespHeaders $hasRespElements $hasRespStringBody $hasRespBinaryBody}} +QsError qs_{{$opID | snakeCase}}({{- if $isObject}}char* objectKey, {{end -}}qs_{{$opID | snakeCase}}_input_t* input, qs_{{$opID | snakeCase}}_output_t* output, qs_context_handle context_hdl) +{ + //init class {{$operation.ID}}inputCpp + {{$operation.ID}}Input inputCpp; + {{$operation.ID}}Output outputCpp; + {{- if $hasBinaryBody}} + std::iostream* reqStreamBody = NULL; + {{- end}} + + // packer cpp input + {{if $hasParams}} + {{- $data := $operation.Request.Query -}} + {{template "ParkProperties" passThrough $data `location:"params"` $operation.ID}} + {{- end -}} + {{if $hasHeaders}} + {{- $data := $operation.Request.Headers -}} + {{template "ParkProperties" passThrough $data `location:"headers"` $operation.ID}} + {{- end -}} + {{if $hasElements}} + {{- $data := $operation.Request.Elements -}} + {{template "ParkProperties" passThrough $data `location:"elements"` $operation.ID}} + {{- end -}} + + {{- if $hasBinaryBody}} + if(input->bodybuf) + { + reqStreamBody = new QsStream(); + reqStreamBody->write(static_cast < char *>(input->bodybuf), + (size_t) * input->bufLength); + inputCpp.SetBody(reqStreamBody); + } + {{- end}} + + // init output + init_{{$operation.ID | snakeCase}}_output(output); + + // call cpp op + {{if or $isBucket $isObject}} + Bucket * qsBucket = (Bucket *)(context_hdl.pQsBucket); + {{else}} + QingStorService * qsService = (QingStorService *)(context_hdl.pQsService); + {{end}} + QsError err ={{- " " -}} + {{- if or $isBucket $isObject -}} + qsBucket-> + {{- else -}} + qsService-> + {{- end -}} + {{$opID}}({{- if $isObject}}objectKey, {{end -}}inputCpp, outputCpp); + if(QS_ERR_NO_ERROR == err) + { + // uppacker cpp output + {{- if $hasRespHeaders}} + {{- $data := allRespnoseHeaders $operation.Responses -}} + {{template "UnParkProperties" passThrough $data `location:"headers"` $operation.ID}} + {{- end}} + + {{- if $hasRespElements}} + {{- $data := allRespnoseElements $operation.Responses -}} + {{template "UnParkProperties" passThrough $data `location:"elements"` $operation.ID}} + {{- end}} + + {{- range $keyStatus, $valueStatus := $operation.Responses -}} + {{- if eq $valueStatus.Body.Type "binary"}} + std::iostream* respStreamBody = outputCpp.GetBody(); + if(respStreamBody) + { + respStreamBody->seekg(0, outputCpp.GetBody()->end); + size_t streamSize = outputCpp.GetBody()->tellg(); + respStreamBody->seekg(0, outputCpp.GetBody()->beg); + + output->bodybuf = (void *)malloc(streamSize); + output->bufLength = (int64_t *)malloc(sizeof(int64_t)); + + //size_t readCount = (streamSize > *output->bufLength)? *output->bufLength : streamSize; + respStreamBody->read((char *)output->bodybuf, streamSize); + *output->bufLength = static_cast(respStreamBody->gcount());; + + //clean up + delete respStreamBody; + } + {{- end -}} + {{- end}} + + output->response_code = (int)outputCpp.GetResponseCode(); + } + else if(QS_ERR_UNEXCEPTED_RESPONSE == err){ + // if got unexcepted response + output->response_code = (int)outputCpp.GetResponseCode(); + ResponseErrorInfo errorInfo = outputCpp.GetResponseErrInfo(); + LOGW <<"Got unexcepted response with code:" << errorInfo.code << " " << errorInfo.message; + qs_set_error_info(&output->error_info, errorInfo); + } + + + {{- if $hasBinaryBody}} + // clean up + if(reqStreamBody){ + delete reqStreamBody; + reqStreamBody = NULL; + } + {{- end}} + + return err; +} +{{end}} + +{{define "ParkProperties"}} + {{- $customizedType := index . 0 -}} + {{- $propertyExtraTags := index . 1 -}} + {{- $operationID := index . 2 -}} + + {{range $_, $property := $customizedType.Properties -}} + if(input->{{$property.Name | snakeCase}}) + { + {{- if eq $property.Type "array"}} + //qs_list_t list_{{$property.ID | snakeCase}}; + //qs_list_init(list_{{$property.ID | snakeCase}}); + + std::vector<{{template "Type" passThrough $property.ExtraType false}}> {{$property.ID | camelCase}}; + qs_{{$property.ExtraType | snakeCase}}_item_t * item; + qs_list_for_each_entry(qs_{{$property.ExtraType | snakeCase}}_item_t, item, input->{{$property.ID | snakeCase}}) + { + {{- $isStringType := eq $property.ExtraType "string" -}} + {{- $isTimeStampType := eq $property.ExtraType "timestamp" -}} + {{- if or $isStringType $isTimeStampType -}} + {{$property.ID | camelCase}}.push_back(*item->content); + {{- else -}} + {{$property.ID | camelCase}}.push_back(*item->content); + {{- end}} + } + + inputCpp.Set{{$property.ID | camelCase}}({{$property.ID | camelCase}}); + {{- else if eq $property.Type "string"}} + inputCpp.Set{{$property.ID | camelCase}}(input->{{$property.Name | snakeCase}}); + {{- else if eq $property.Type "timestamp"}} + inputCpp.Set{{$property.ID | camelCase}}(input->{{$property.Name | snakeCase}}); + {{- else -}} + inputCpp.Set{{$property.ID | camelCase}}(*input->{{$property.Name | snakeCase}}); + {{end}} + } + {{end}} +{{end}} + +{{define "UnParkProperties"}} + {{- $properties := index . 0 -}} + {{- $propertyExtraTags := index . 1 -}} + {{- $operationID := index . 2 -}} + + {{range $_, $property := $properties -}} + {{- $isStringType := eq $property.Type "string" -}} + {{- $isTimeStampType := eq $property.Type "timestamp" -}} + {{- $isIntegerType := eq $property.Type "integer" -}} + {{- $isLongType := eq $property.Type "long" -}} + {{- $isBoolType := eq $property.Type "boolean" -}} + {{- $isStringExtraType := eq $property.ExtraType "string" -}} + {{- $isTimeStampExtraType := eq $property.ExtraType "timestamp" -}} + {{- $isIntegerExtraType := eq $property.ExtraType "integer" -}} + + {{- if eq $property.Type "array"}} + output->{{$property.Name | snakeCase}} = (qs_list_t *)malloc(sizeof(qs_list_t)); + qs_list_init(output->{{$property.Name | snakeCase}}); + std::vector<{{template "Type" passThrough $property.ExtraType false}}> {{$property.ID | camelCase| lowerFirstWord}} = outputCpp.Get{{$property.ID | camelCase}}(); + for(std::vector<{{- template "Type" passThrough $property.ExtraType true}}>::iterator it = {{$property.ID | camelCase| lowerFirstWord}}.begin(); it != {{$property.ID | camelCase| lowerFirstWord}}.end(); it++) + { + qs_{{$property.ExtraType | snakeCase}}_item_t* item = (qs_{{$property.ExtraType | snakeCase}}_item_t*)malloc(sizeof(qs_{{$property.ExtraType | snakeCase}}_item_t)); + + {{- if or $isStringExtraType $isTimeStampExtraType}} + int {{$property.ID | camelCase}}Length = it->length(); + if({{$property.ID | camelCase}}Length > 0){ + item->content = (char *)malloc({{$property.ID | camelCase}}Length +1); + memset(item->content, 0 ,{{$property.ID | camelCase}}Length +1); + item->content = (char *)malloc({{$property.ID | camelCase}}Length +1); + strncpy(item->content, it->c_str(), {{$property.ID | camelCase}}Length); + }else{ + item->content = NULL; + } + {{else if $isIntegerExtraType}} + //item->content = it; + {{else}} + item->content = it->toCStyleObj(); + {{end}} + qs_list_append(&item->node, output->{{$property.Name | snakeCase}}); + } + + {{- else if or $isStringType $isTimeStampType}} + int {{$property.ID | camelCase}}Length = outputCpp.Get{{$property.ID | camelCase}}().length(); + if({{$property.ID | camelCase}}Length > 0){ + output->{{$property.Name | snakeCase}} = (char *)malloc({{$property.ID | camelCase}}Length +1); + memset(output->{{$property.Name | snakeCase}}, 0 ,{{$property.ID | camelCase}}Length +1); + strncpy(output->{{$property.Name | snakeCase}}, outputCpp.Get{{$property.ID | camelCase}}().c_str(), {{$property.ID | camelCase}}Length); + }else{ + output->{{$property.Name | snakeCase}} = NULL; + } + {{- else if or $isIntegerType $isLongType $isBoolType}} + output->{{$property.Name | snakeCase}} = ({{template "Type" passThrough $property.Type false}} *)malloc(sizeof({{template "Type" passThrough $property.Type false}})); + *output->{{$property.Name | snakeCase}} = outputCpp.Get{{$property.ID | camelCase}}(); + {{- else -}} + output->{{$property.Name | snakeCase}} = outputCpp.Get{{$property.ID | camelCase}}().toCStyleObj(); + {{end}} + {{end}} +{{end}} + +{{define "AssignmentProperties"}} + {{- $customizedType := index . 0 -}} + {{- $propertyExtraTags := index . 1 -}} + {{- $operationID := index . 2 -}} + + {{range $_, $property := $customizedType.Properties -}} + {{- if eq $property.Type "array"}} + pInput->{{$property.Name | camelCase}}Count; + std::vector<> + + input.Set{{$property.ID | camelCase}}(pInput->{{$property.Name | camelCase}}); + {{- else }} + input.Set{{$property.ID | camelCase}}(pInput->{{$property.Name | camelCase}}); + {{end}} + {{end}} +{{end}} + +{{define "RequestSource"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | camelCase -}} + {{- $belongs := replace $service.Name "QingStor" "Service" -1 -}} + {{- $belongs := replace $belongs "Object" "Bucket" -1 -}} + {{- $uri := $operation.Request.URI -}} + {{- $uri := replace $uri "{" "<" -1 -}} + {{- $uri := replace $uri "}" ">" -1 -}} + {{- $uri := dashConnected $uri -}} + {{- $hasParams := gt (len $operation.Request.Query.Properties) 0 -}} + {{- $hasHeaders := gt (len $operation.Request.Headers.Properties) 0 -}} + {{- $hasElements := gt (len $operation.Request.Elements.Properties) 0 -}} + {{- $hasStringBody := eq $operation.Request.Body.Type "string" -}} + {{- $hasBinaryBody := eq $operation.Request.Body.Type "binary" -}} + {{- $hasInput := or $hasParams $hasHeaders $hasElements $hasStringBody $hasBinaryBody}} + {{- $hasRespHeaders := gt (len $operation.Response.Headers.Properties) 0 -}} + {{- $hasRespElements := gt (len $operation.Response.Elements.Properties) 0 -}} + {{- $hasRespStringBody := eq $operation.Response.Body.Type "string" -}} + {{- $hasRespBinaryBody := eq $operation.Response.Body.Type "binary" -}} + {{- $hasOutput := or $hasRespHeaders $hasRespElements $hasRespStringBody $hasRespBinaryBody}} + +class {{$opID | camelCase}}Request:public QsRequest +{ +public: + {{$opID}}Request(const Operation& op, const {{$operation.ID}}Input& input); + + virtual ~{{$opID}}Request(){}; + + {{$opID}}Output GetOutput(); + + {{- if $hasElements}} + std::string SerializePayload(); + {{- end}} + {{- if $hasParams}} + Http::QueryParamCollection GetQueryParameters(); + {{- end}} + {{- if $hasHeaders}} + Http::HeaderValueCollection GetRequestSpecificHeaders(); + {{- end}} + {{- if $hasRespHeaders}} + void ParseResponseHeaders(HttpResponse& response); + {{- end}} + {{- if $hasRespElements}} + void ParseResponseElements(HttpResponse& response); + {{- end}} + {{- if or $hasRespStringBody $hasRespBinaryBody}} + void ParseResponseBody(HttpResponse& response); + {{- end}} + +private: + {{$operation.ID}}Input m_input; + {{$operation.ID}}Output m_output; +}; + +// {{$opID}}Request Constructor. +{{$opID}}Request::{{$opID}}Request(const Operation& op, const {{$opID}}Input& input):m_input(input),QsRequest(op) +{ + //TO DO; +} + +{{$opID}}Output {{$opID}}Request::GetOutput() +{ + m_output.SetErr(QsRequest::Send()); + return m_output; +} + +{{- if $hasElements}} +// {{$opID}}Request SerializePayload. +std::string {{$opID}}Request::SerializePayload() +{ +/* + {{- if eq (len $operation.Request.Elements.Properties) 0 }} + rerutn ""; + {{- else -}} + //TO DO; + JsonValue payload; + + {{range $_, $BodyPropertie := $operation.Request.Elements.Properties -}} + {{- $PpropertyName := $BodyPropertie.ID | camelCase -}} + {{- if eq $BodyPropertie.Type "array" -}} + Array {{$PpropertyName}}JsonList(m_{{$PpropertyName}}.size()); + for(unsigned {{$PpropertyName}}Index = 0; {{$PpropertyName}}Index < {{$PpropertyName}}JsonList.GetLength(); + ++{{$PpropertyName}}Index) + { + {{$PpropertyName}}JsonList[{{$PpropertyName}}Index].AsString(m_{{$PpropertyName}}[{{$PpropertyName}}Index]); + } + payload.WithArray("{{$BodyPropertie.ID}}", std::move(m_{{$PpropertyName}}List)); + {{- else -}} + it = find( PropsHasBeenSet.begin(), PropsHasBeenSet.end(), "{{$BodyPropertie.ID}}" ); + if( it != PropsHasBeenSet.end() ) // finded + { + payload.WithString("{{$BodyPropertie.ID}}", m_{{$PpropertyName}}); + } + {{- end -}} + {{end}} + return payload.WriteReadble(); + {{end}} + */ +} +{{- end -}} + +{{- if $hasParams}} +// {{$opID}}Request AddQueryStringParameters. +Http::QueryParamCollection {{$opID}}Request::GetQueryParameters() +{ + Http::QueryParamCollection queryParameters; + + std::stringstream ss; + std::vector::iterator it; + + {{range $_, $QueryPropertie := $operation.Request.Query.Properties}} + if(m_input.IsPropHasBeenSet("{{$QueryPropertie.ID}}")) + { + ss << m_input.Get{{$QueryPropertie.ID | camelCase}}(); + queryParameters.insert(Http::HeaderValuePair("{{$QueryPropertie.ID}}", ss.str())); + ss.str(""); + } + {{end -}} + + return queryParameters; +} +{{- end -}} + + +{{- if $hasHeaders}} +// {{$opID}}Request GetRequestSpecificHeaders. +Http::HeaderValueCollection {{$opID}}Request::GetRequestSpecificHeaders() +{ + //TO DO; + Http::HeaderValueCollection headers; + std::stringstream ss; + std::vector::iterator it; + + {{range $_, $HeaderPropertie := $operation.Request.Headers.Properties}} + if(m_input.IsPropHasBeenSet("{{$HeaderPropertie.ID}}")) + { + ss << m_input.Get{{$HeaderPropertie.ID | camelCase}}(); + headers.insert(Http::HeaderValuePair("{{$HeaderPropertie.ID}}", ss.str())); + ss.str(""); + } + {{end -}} + + return headers; +} +{{- end -}} + +{{- if $hasRespHeaders}} +// {{$opID}}Request ParseResponseHeaders. +void {{$opID}}Request::ParseResponseHeaders(HttpResponse& response) +{ + const auto& headers = response.GetHeaders(); + + {{range $_, $respHeaderPropertie := $operation.Response.Headers.Properties}} + const auto& {{$respHeaderPropertie.ID | camelCase}}Iter = headers.find("{{$respHeaderPropertie.ID}}"); + if({{$respHeaderPropertie.ID | camelCase}}Iter != headers.end()) + { + {{if eq $respHeaderPropertie.Type "string" -}} + m_output.Set{{$respHeaderPropertie.ID | camelCase}}({{$respHeaderPropertie.ID | camelCase}}Iter->second); + {{else}} + m_output.Set{{$respHeaderPropertie.ID | camelCase}}( + {{- template "RenderTypeTransFuns" passThrough $respHeaderPropertie -}} + ({{$respHeaderPropertie.ID | camelCase}}Iter->second.c_str())); + {{end}} + } + {{end}} +} +{{- end -}} + +{{- if $hasRespElements}} +void {{$opID}}Request::ParseResponseElements(HttpResponse& response) +{ +/* + // parse json content + const JsonValue& jsonValue(response.GetResponseBody()); + + {{range $_, $RespElementPropert := $operation.Response.Elements.Properties -}} + {{- $ElementName := $RespElementPropert.ID | camelCase | lowerFirstWord}} + if(jsonValue.ValueExits("{{$ElementName}}")) + { + {{if eq $RespElementPropert.Type "array"}} + Array {{$ElementName}}List = jsonValue.GetArray({{$ElementName}}); + + {{template "RequestPropertyType" passThrough $RespElementPropert false}} tmp{{$ElementName}}; + + for(unsigned {{$ElementName}}Index = 0; {{$ElementName}}Index < {{$ElementName}}List.GetLength(); ++{{$ElementName}}Index) + { + tmp{{$ElementName}};.push_back({{$ElementName}}List.AsObject()); + } + m_output.Set{{$ElementName}}(tmp{{$ElementName}}); + {{- else -}} + m_output.Set{{$ElementName}}(jsonValue.GetString({{$ElementName}})); + {{- end}} + } + {{end}} + */ +} +{{- end -}} + +{{- if or $hasRespStringBody $hasRespBinaryBody}} +void {{$opID}}Request::ParseResponseBody(HttpResponse& response) +{ + m_output.SetContentBody(response.GetResponseBody()); +} +{{- end -}} +{{- end -}} + +{{define "ResultSource"}} + {{- $service := index . 0 -}} + {{- $operation := index . 1 -}} + {{- $opID := $operation.ID | camelCase -}} + {{- $belongs := replace $service.Name "QingStor" "Service" -1 -}} + {{- $belongs := replace $belongs "Object" "Bucket" -1 -}} + {{- $uri := $operation.Request.URI -}} + {{- $uri := replace $uri "{" "<" -1 -}} + {{- $uri := replace $uri "}" ">" -1 -}} + {{- $uri := dashConnected $uri -}} + + {{- $hasParams := gt (len $operation.Request.Query.Properties) 0 -}} + {{- $hasHeaders := gt (len $operation.Request.Headers.Properties) 0 -}} + {{- $hasElements := gt (len $operation.Request.Elements.Properties) 0 -}} + {{- $hasStringBody := eq $operation.Request.Body.Type "string" -}} + {{- $hasBinaryBody := eq $operation.Request.Body.Type "binary" -}} + {{- $hasInput := or $hasParams $hasHeaders $hasElements $hasStringBody $hasBinaryBody -}} + +// {{$opID}}Result Constructor. +{{$opID}}Result::{{$opID}}Result() +{ + //TO DO; +} + +void {{$opID}}Result::BuildFromResp(const std::shared_ptr& httpResponse) +{ + //TO DO; +{{if $hasInput}} + + // build body + m_body = httpResponse.GetResponseBody(); + {{if $operation.Response.Elements.Properties | len}} + // parse json content + const JsonValue& jsonValue(httpResponse.GetResponseBody()); + + {{range $_, $RespElementPropert := $operation.Response.Elements.Properties -}} + {{- $ElementName := $RespElementPropert.ID | camelCase | lowerFirstWord}} + if(jsonValue.ValueExits("{{$ElementName}}")) + { + {{if eq $RespElementPropert.Type "array"}} + Array {{$ElementName}}List = jsonValue.GetArray({{$ElementName}}); + for(unsigned {{$ElementName}}Index = 0; {{$ElementName}}Index < {{$ElementName}}List.GetLength(); ++{{$ElementName}}Index) + { + m_{{$ElementName}}.push_back({{$ElementName}}List.AsObject()); + } + {{else}} + m_{{$ElementName}} = jsonValue.GetString({$ElementName}}); + {{end}} + } + {{- end -}} + {{- end -}} + {{if $operation.Response.Headers.Properties | len}} + // build http header + const auto& headers = result.GetHeaderValueCollection(); + {{range $_, $RespHeader := $operation.Response.Headers.Properties -}} + {{- $HeaderName := $RespHeader.ID | camelCase}} + + const auto& {{$HeaderName}}Iter = headers.find({{$RespHeader.ID}}); + if({{$HeaderName}}Iter != headers.end()) + { + {{if eq $RespHeader.Type "string" -}} + m_{{$HeaderName}} = {{$HeaderName}}Iter->second; + {{- else if eq $RespHeader.Type "timestamp" -}} + #elseif($memberEntry.value.shape.timeStamp) + m_{{$HeaderName}} = DateTime(${varName}Iter->second.c_str(), DateFormat::RFC822); + {{- else if eq $RespHeader.Type "integer" -}} + m_{{$HeaderName}} = std::atoi({{$HeaderName}}Iter->second.c_str()); + {{- else if eq $RespHeader.Type "boolean" -}} + std::istringstream({$HeaderName}}Iter->second) >> std::boolalpha >> b; + {{- else -}} + ????????????????????????????????????? + {{end}} + } + {{- end -}} + {{- end -}} +{{else}} + (void)httpResponseï¼› +{{end}} + + return; +} + +{{end}} + +{{define "RequestPropertyType"}} + {{- $property := index . 0 -}} + {{- $disablePointer := index . 1 -}} + + {{- if eq $property.Type "object"}} + {{template "Type" passThrough $property.ExtraType $disablePointer}} + {{- else if eq $property.Type "array"}} + std::vector<{{template "Type" passThrough $property.ExtraType $disablePointer}}> + {{- else if eq $property.Type "map"}} + Map[string]{{template "Type" passThrough $property.ExtraType $disablePointer}} + {{- else if eq $property.Type "any"}} + {{template "Type" passThrough $property.Type $disablePointer}} + {{- else -}} + {{template "Type" passThrough $property.Type $disablePointer}} + {{- end -}} +{{end}} + +{{define "RenderTypeTransFuns"}} + {{- $property := index . 0 -}} + {{- $typeName := $property.Type -}} + + {{- if eq $typeName "boolean" -}} + StringUtils::ConvertToBool + {{- else if eq $typeName "integer" -}} + StringUtils::ConvertToInt32 + {{- else if eq $typeName "timestamp" -}} + DateTime + {{- end -}} +{{end}} + +{{define "Type"}} + {{- $typeName := index . 0 -}} + {{- $disablePointer := index . 1 -}} + + {{- if eq $typeName "string" -}} + std::string{{" " -}} + {{- else if eq $typeName "boolean" -}} + _Bool{{" " -}} + {{- else if eq $typeName "integer" -}} + int{{" " -}} + {{- else if eq $typeName "long" -}} + long {{" " -}} + {{- else if eq $typeName "timestamp" -}} + time_t{{" " -}} + {{- else if eq $typeName "binary" -}} + char{" " -}}* + {{- else if eq $typeName "array" -}} + std::vector<> + {{- else if eq $typeName "object" -}} + interface{} + {{- else if eq $typeName "map" -}} + interface{} + {{- else if eq $typeName "any" -}} + interface{} + {{- else -}} + {{$typeName | camelCase}}Type{{" " -}} + {{- end -}} +{{end}} + +{{define "PropertyType"}} + {{- $property := index . 0 -}} + {{- $disablePointer := index . 1 -}} + + {{- if eq $property.Type "object" -}} + {{template "Type" passThrough $property.ExtraType $disablePointer}} + {{- else if eq $property.Type "array" -}} + []{{template "Type" passThrough $property.ExtraType $disablePointer}} + {{- else if eq $property.Type "map" -}} + map[string]{{template "Type" passThrough $property.ExtraType $disablePointer}} + {{- else if eq $property.Type "any" -}} + {{template "Type" passThrough $property.Type $disablePointer}} + {{- else -}} + {{template "Type" passThrough $property.Type $disablePointer}} + {{- end -}} +{{end}} + +{{define "PropertyTags"}} + {{- $property := . -}} + {{- if $property.IsRequired -}} + {{- printf `json:"%s"` ($property.Name | normalized) -}} + {{- else -}} + {{- printf `json:"%s,omitempty"` ($property.Name | normalized) -}} + {{- end -}} + {{- printf ` name:"%s"` ($property.Name | normalized) -}} + {{- if $property.Format}} + {{- printf ` format:"%s"` $property.Format -}} + {{- end -}} + {{- if $property.Default -}} + {{- printf ` default:"%s"` $property.Default -}} + {{- end -}} +{{end}} + +{{define "PropertyExtraTags"}} + {{- $propertyExtraTags := . -}} + {{- if $propertyExtraTags -}} + {{- printf " %s" $propertyExtraTags -}} + {{- end -}} +{{end}} diff --git a/template/source_with_c_style/types.tmpl b/template/source_with_c_style/types.tmpl new file mode 100644 index 0000000..f20c35f --- /dev/null +++ b/template/source_with_c_style/types.tmpl @@ -0,0 +1,28 @@ +// +------------------------------------------------------------------------- +// | Copyright (C) 2017 Yunify, Inc. +// +------------------------------------------------------------------------- +// | Licensed under the Apache License, Version 2.0 (the "License"); +// | you may not use this work except in compliance with the License. +// | You may obtain a copy of the License in the LICENSE file, or 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. +// +------------------------------------------------------------------------- + +{{- $service := .Data.Service}} +{{- $objectSubService := index .Data.SubServices "Object"}} +{{- $customizedTypes := .Data.CustomizedTypes}} +{{- $currentTypeID := .CurrentSubServiceID}} + +// Headers of CustomizedType. +#include "service_with_c_style/Types.h" + +{{range $_, $customizedType := $customizedTypes -}} +{{template "CustomTypeInitFun" passThrough $customizedType}} +{{template "CustomTypeReleaseFun" passThrough $customizedType}} +{{end}} diff --git a/test/CMake/FindGMock.cmake b/test/CMake/FindGMock.cmake new file mode 100644 index 0000000..b8f2c80 --- /dev/null +++ b/test/CMake/FindGMock.cmake @@ -0,0 +1,501 @@ +# Get the Google C++ Mocking Framework. +# (This file is almost an copy of the original FindGTest.cmake file, +# altered to download and compile GMock and GTest if not found +# in GMOCK_ROOT or GTEST_ROOT respectively, +# feel free to use it as it is or modify it for your own needs.) +# +# Defines the following variables: +# +# GMOCK_FOUND - Found or got the Google Mocking framework +# GTEST_FOUND - Found or got the Google Testing framework +# GMOCK_INCLUDE_DIRS - GMock include directory +# GTEST_INCLUDE_DIRS - GTest include direcotry +# +# Also defines the library variables below as normal variables +# +# GMOCK_BOTH_LIBRARIES - Both libgmock & libgmock_main +# GMOCK_LIBRARIES - libgmock +# GMOCK_MAIN_LIBRARIES - libgmock-main +# +# GTEST_BOTH_LIBRARIES - Both libgtest & libgtest_main +# GTEST_LIBRARIES - libgtest +# GTEST_MAIN_LIBRARIES - libgtest_main +# +# Accepts the following variables as input: +# +# GMOCK_ROOT - The root directory of the gmock install prefix +# GTEST_ROOT - The root directory of the gtest install prefix +# GMOCK_SRC_DIR -The directory of the gmock sources +# GMOCK_VER - The version of the gmock sources to be downloaded +# +#----------------------- +# Example Usage: +# +# set(GMOCK_ROOT "~/gmock") +# find_package(GMock REQUIRED) +# include_directories(${GMOCK_INCLUDE_DIRS}) +# +# add_executable(foo foo.cc) +# target_link_libraries(foo ${GMOCK_BOTH_LIBRARIES}) +# +#============================================================================= +# Copyright (c) 2016 Michel Estermann +# Copyright (c) 2016 Kamil Strzempowicz +# Copyright (c) 2011 Matej Svec +# +# CMake - Cross Platform Makefile Generator +# Copyright 2000-2016 Kitware, Inc. +# Copyright 2000-2011 Insight Software Consortium +# 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 names of Kitware, Inc., the Insight Software Consortium, +# nor the names of their 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 +# 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. +# +# ------------------------------------------------------------------------------ +# +# The above copyright and license notice applies to distributions of +# CMake in source and binary form. Some source files contain additional +# notices of original copyright by their contributors; see each source +# for details. Third-party software packages supplied with CMake under +# compatible licenses provide their own copyright notices documented in +# corresponding subdirectories. +# +# ------------------------------------------------------------------------------ +# +# CMake was initially developed by Kitware with the following sponsorship: +# +# * National Library of Medicine at the National Institutes of Health +# as part of the Insight Segmentation and Registration Toolkit (ITK). +# +# * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel +# Visualization Initiative. +# +# * National Alliance for Medical Image Computing (NAMIC) is funded by the +# National Institutes of Health through the NIH Roadmap for Medical Research, +# Grant U54 EB005149. +# +# * Kitware, Inc. +#============================================================================= +# Thanks to Daniel Blezek for the GTEST_ADD_TESTS code + +function(gtest_add_tests executable extra_args) +if(NOT ARGN) + message(FATAL_ERROR "Missing ARGN: Read the documentation for GTEST_ADD_TESTS") + endif() + if(ARGN STREQUAL "AUTO") +# obtain sources used for building that executable + get_property(ARGN TARGET $ {executable} PROPERTY SOURCES) + endif() + set(gtest_case_name_regex ".*\\( *([A-Za-z_0-9]+) *, *([A-Za-z_0-9]+) *\\).*") + set(gtest_test_type_regex "(TYPED_TEST|TEST_?[FP]?)") + foreach(source $ {ARGN}) + file(READ "${source}" contents) + string(REGEX MATCHALL "${gtest_test_type_regex} *\\(([A-Za-z_0-9 ,]+)\\)" found_tests $ {contents}) + foreach(hit $ {found_tests}) + string(REGEX MATCH "${gtest_test_type_regex}" test_type $ {hit}) + +# Parameterized tests have a different signature for the filter + if("x${test_type}" STREQUAL "xTEST_P") + string(REGEX REPLACE $ {gtest_case_name_regex} "*/\\1.\\2/*" test_name $ {hit}) + elseif("x${test_type}" STREQUAL "xTEST_F" OR "x${test_type}" STREQUAL "xTEST") + string(REGEX REPLACE $ {gtest_case_name_regex} "\\1.\\2" test_name $ {hit}) + elseif("x${test_type}" STREQUAL "xTYPED_TEST") + string(REGEX REPLACE $ {gtest_case_name_regex} "\\1/*.\\2" test_name $ {hit}) + else() + message(WARNING "Could not parse GTest ${hit} for adding to CTest.") + continue() + endif() + add_test(NAME $ {test_name} COMMAND $ {executable} --gtest_filter=$ {test_name} $ {extra_args}) + endforeach() + endforeach() + endfunction() + + function(_append_debugs _endvar _library) + if($ {_library} AND $ {_library} _DEBUG) + set(_output optimized $ {${_library}} debug $ {${_library} _DEBUG}) + else() + set(_output $ {${_library}}) + endif() + set($ {_endvar} $ {_output} PARENT_SCOPE) + endfunction() + + function(_gmock_find_library _name) + find_library($ {_name} + NAMES $ {ARGN} + HINTS + ENV GMOCK_ROOT + $ {GMOCK_ROOT} + PATH_SUFFIXES $ {_gmock_libpath_suffixes} + ) + mark_as_advanced($ {_name}) + endfunction() + + function(_gtest_find_library _name) + find_library($ {_name} + NAMES $ {ARGN} + HINTS + ENV GTEST_ROOT + $ {GTEST_ROOT} + PATH_SUFFIXES $ {_gtest_libpath_suffixes} + ) + mark_as_advanced($ {_name}) + endfunction() + + if(NOT DEFINED GMOCK_MSVC_SEARCH) + set(GMOCK_MSVC_SEARCH MD) + endif() + + set(_gmock_libpath_suffixes lib) + set(_gtest_libpath_suffixes lib) + if(MSVC) + if(GMOCK_MSVC_SEARCH STREQUAL "MD") + list(APPEND _gmock_libpath_suffixes + msvc/gmock-md/Debug + msvc/gmock-md/Release) + list(APPEND _gtest_libpath_suffixes + msvc/gtest-md/Debug + msvc/gtest-md/Release) + elseif(GMOCK_MSVC_SEARCH STREQUAL "MT") + list(APPEND _gmock_libpath_suffixes + msvc/gmock/Debug + msvc/gmock/Release) + list(APPEND _gtest_libpath_suffixes + msvc/gtest/Debug + msvc/gtest/Release) + endif() + endif() + + find_path(GMOCK_INCLUDE_DIR gmock/gmock.h + HINTS + $ENV{GMOCK_ROOT}/include + $ {GMOCK_ROOT}/include + ) + mark_as_advanced(GMOCK_INCLUDE_DIR) + + find_path(GTEST_INCLUDE_DIR gtest/gtest.h + HINTS + $ENV{GTEST_ROOT}/include + $ {GTEST_ROOT}/include + ) + mark_as_advanced(GTEST_INCLUDE_DIR) + + if(MSVC AND GMOCK_MSVC_SEARCH STREQUAL "MD") +# The provided /MD project files for Google Mock add -md suffixes to the +# library names. + _gmock_find_library(GMOCK_LIBRARY gmock-md gmock) + _gmock_find_library(GMOCK_LIBRARY_DEBUG gmock-mdd gmockd) + _gmock_find_library(GMOCK_MAIN_LIBRARY gmock_main-md gmock_main) + _gmock_find_library(GMOCK_MAIN_LIBRARY_DEBUG gmock_main-mdd gmock_maind) + + _gtest_find_library(GTEST_LIBRARY gtest-md gtest) + _gtest_find_library(GTEST_LIBRARY_DEBUG gtest-mdd gtestd) + _gtest_find_library(GTEST_MAIN_LIBRARY gtest_main-md gtest_main) + _gtest_find_library(GTEST_MAIN_LIBRARY_DEBUG gtest_main-mdd gtest_maind) + else() + _gmock_find_library(GMOCK_LIBRARY gmock) + _gmock_find_library(GMOCK_LIBRARY_DEBUG gmockd) + _gmock_find_library(GMOCK_MAIN_LIBRARY gmock_main) + _gmock_find_library(GMOCK_MAIN_LIBRARY_DEBUG gmock_maind) + + _gtest_find_library(GTEST_LIBRARY gtest) + _gtest_find_library(GTEST_LIBRARY_DEBUG gtestd) + _gtest_find_library(GTEST_MAIN_LIBRARY gtest_main) + _gtest_find_library(GTEST_MAIN_LIBRARY_DEBUG gtest_maind) + endif() + + if(NOT TARGET GTest::GTest) + add_library(GTest::GTest UNKNOWN IMPORTED) + endif() + if(NOT TARGET GTest::Main) + add_library(GTest::Main UNKNOWN IMPORTED) + endif() + + if(NOT TARGET GMock::GMock) + add_library(GMock::GMock UNKNOWN IMPORTED) + endif() + + if(NOT TARGET GMock::Main) + add_library(GMock::Main UNKNOWN IMPORTED) + endif() + + set(GMOCK_LIBRARY_EXISTS OFF) + set(GTEST_LIBRARY_EXISTS OFF) + + if(EXISTS "${GMOCK_LIBRARY}" OR EXISTS "${GMOCK_LIBRARY_DEBUG}" AND GMOCK_INCLUDE_DIR) + set(GMOCK_LIBRARY_EXISTS ON) + endif() + + if(EXISTS "${GTEST_LIBRARY}" OR EXISTS "${GTEST_LIBRARY_DEBUG}" AND GTEST_INCLUDE_DIR) + set(GTEST_LIBRARY_EXISTS ON) + endif() + + if(NOT ($ {GMOCK_LIBRARY_EXISTS} AND $ {GTEST_LIBRARY_EXISTS})) + + include(ExternalProject) + + if(GTEST_USE_STATIC_LIBS) + set(GTEST_CMAKE_ARGS -Dgtest_force_shared_crt:BOOL=ON -DBUILD_SHARED_LIBS=OFF) + set(GTEST_LIBRARY_PREFIX $ {CMAKE_STATIC_LIBRARY_PREFIX}) + else() + set(GTEST_CMAKE_ARGS -DBUILD_SHARED_LIBS=ON) + set(GTEST_LIBRARY_PREFIX $ {CMAKE_SHARED_LIBRARY_PREFIX}) + endif() + + if("${GMOCK_SRC_DIR}" STREQUAL "") + message(STATUS "Downloading GMock / GTest version ${GMOCK_VER} from git") + if("${GMOCK_VER}" STREQUAL "1.6.0" OR "${GMOCK_VER}" STREQUAL "1.7.0") + set(GTEST_BIN_DIR "${GMOCK_ROOT}/src/gtest-build") + set(GTEST_LIBRARY "${GTEST_BIN_DIR}/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}") + set(GTEST_MAIN_LIBRARY "${GTEST_BIN_DIR}/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX}") + mark_as_advanced(GTEST_LIBRARY) + mark_as_advanced(GTEST_MAIN_LIBRARY) + + externalproject_add( + gtest + GIT_REPOSITORY "https://github.com/google/googletest.git" + GIT_TAG "release-${GMOCK_VER}" + PREFIX $ {GMOCK_ROOT} + INSTALL_COMMAND "" + LOG_DOWNLOAD ON + LOG_CONFIGURE ON + LOG_BUILD ON + CMAKE_ARGS + -Dgtest_disable_pthreads=$ {MINGW} + $ {GTEST_CMAKE_ARGS} + BINARY_DIR $ {GTEST_BIN_DIR} + BUILD_BYPRODUCTS + "${GTEST_LIBRARY}" + "${GTEST_MAIN_LIBRARY}" + ) + + set(GMOCK_BIN_DIR "${GMOCK_ROOT}/src/gmock-build") + set(GMOCK_LIBRARY "${GMOCK_BIN_DIR}/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gmock${CMAKE_STATIC_LIBRARY_SUFFIX}") + set(GMOCK_MAIN_LIBRARY "${GMOCK_BIN_DIR}/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gmock_main${CMAKE_STATIC_LIBRARY_SUFFIX}") + mark_as_advanced(GMOCK_LIBRARY) + mark_as_advanced(GMOCK_MAIN_LIBRARY) + + externalproject_add( + gmock + GIT_REPOSITORY "https://github.com/google/googlemock.git" + GIT_TAG "release-${GMOCK_VER}" + PREFIX $ {GMOCK_ROOT} + INSTALL_COMMAND "" + LOG_DOWNLOAD ON + LOG_CONFIGURE ON + LOG_BUILD ON + CMAKE_ARGS + -Dgtest_disable_pthreads=$ {MINGW} + $ {GTEST_CMAKE_ARGS} + BINARY_DIR $ {GMOCK_BIN_DIR} + BUILD_BYPRODUCTS + "${GMOCK_LIBRARY}" + "${GMOCK_MAIN_LIBRARY}" + ) + + add_dependencies(gmock gtest) + + add_dependencies(GTest::GTest gtest) + add_dependencies(GTest::Main gtest) + add_dependencies(GMock::GMock gmock) + add_dependencies(GMock::Main gmock) + + externalproject_get_property(gtest source_dir) + set(GTEST_INCLUDE_DIR "${source_dir}/include") + mark_as_advanced(GTEST_INCLUDE_DIR) + externalproject_get_property(gmock source_dir) + set(GMOCK_INCLUDE_DIR "${source_dir}/include") + mark_as_advanced(GMOCK_INCLUDE_DIR) + else() #1.8.0 + set(GMOCK_BIN_DIR "${GMOCK_ROOT}/src/gmock-build") + set(GTEST_LIBRARY "${GMOCK_BIN_DIR}/googlemock/gtest/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}") + set(GTEST_MAIN_LIBRARY "${GMOCK_BIN_DIR}/googlemock/gtest/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX}") + set(GMOCK_LIBRARY "${GMOCK_BIN_DIR}/googlemock/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gmock${CMAKE_STATIC_LIBRARY_SUFFIX}") + set(GMOCK_MAIN_LIBRARY "${GMOCK_BIN_DIR}/googlemock/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gmock_main${CMAKE_STATIC_LIBRARY_SUFFIX}") + mark_as_advanced(GTEST_LIBRARY) + mark_as_advanced(GTEST_MAIN_LIBRARY) + mark_as_advanced(GMOCK_LIBRARY) + mark_as_advanced(GMOCK_MAIN_LIBRARY) + + externalproject_add( + gmock + GIT_REPOSITORY "https://github.com/google/googletest.git" + GIT_TAG "release-${GMOCK_VER}" + PREFIX $ {GMOCK_ROOT} + INSTALL_COMMAND "" + LOG_DOWNLOAD ON + LOG_CONFIGURE ON + LOG_BUILD ON + CMAKE_ARGS + -Dgtest_disable_pthreads=$ {MINGW} + $ {GTEST_CMAKE_ARGS} + BINARY_DIR "${GMOCK_BIN_DIR}" + BUILD_BYPRODUCTS + "${GTEST_LIBRARY}" + "${GTEST_MAIN_LIBRARY}" + "${GMOCK_LIBRARY}" + "${GMOCK_MAIN_LIBRARY}" + ) + + add_dependencies(GTest::GTest gmock) + add_dependencies(GTest::Main gmock) + add_dependencies(GMock::GMock gmock) + add_dependencies(GMock::Main gmock) + + externalproject_get_property(gmock source_dir) + set(GTEST_INCLUDE_DIR "${source_dir}/googletest/include") + set(GMOCK_INCLUDE_DIR "${source_dir}/googlemock/include") + mark_as_advanced(GMOCK_INCLUDE_DIR) + mark_as_advanced(GTEST_INCLUDE_DIR) + endif() + +# Prevent CMake from complaining about these directories missing when the libgtest/libgmock targets get used as dependencies + file(MAKE_DIRECTORY $ {GTEST_INCLUDE_DIR} $ {GMOCK_INCLUDE_DIR}) + else() + message(STATUS "Building Gmock / Gtest from dir ${GMOCK_SRC_DIR}") + + set(GMOCK_BIN_DIR "${GMOCK_ROOT}/src/gmock-build") + set(GTEST_LIBRARY "${GMOCK_BIN_DIR}/gtest/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}") + set(GTEST_MAIN_LIBRARY "${GMOCK_BIN_DIR}/gtest/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX}") + set(GMOCK_LIBRARY "${GMOCK_BIN_DIR}/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gmock${CMAKE_STATIC_LIBRARY_SUFFIX}") + set(GMOCK_MAIN_LIBRARY "${GMOCK_BIN_DIR}/${CMAKE_CFG_INTDIR}/${GTEST_LIBRARY_PREFIX}gmock_main${CMAKE_STATIC_LIBRARY_SUFFIX}") + mark_as_advanced(GTEST_LIBRARY) + mark_as_advanced(GTEST_MAIN_LIBRARY) + mark_as_advanced(GMOCK_LIBRARY) + mark_as_advanced(GMOCK_MAIN_LIBRARY) + + if(EXISTS "${GMOCK_SRC_DIR}/gtest/include/gtest/gtest.h") + set(GTEST_INCLUDE_DIR "${GMOCK_SRC_DIR}/gtest/include") + mark_as_advanced(GTEST_INCLUDE_DIR) + endif() + if(EXISTS "${GMOCK_SRC_DIR}/include/gmock/gmock.h") + set(GMOCK_INCLUDE_DIR "${GMOCK_SRC_DIR}/include") + mark_as_advanced(GMOCK_INCLUDE_DIR) + elseif(EXISTS "${GMOCK_SRC_DIR}/../../include/gmock/gmock.h") + set(GMOCK_INCLUDE_DIR "${GMOCK_SRC_DIR}/../../include") + if(IS_ABSOLUTE "${GMOCK_INCLUDE_DIR}") + get_filename_component(GMOCK_INCLUDE_DIR "${GMOCK_INCLUDE_DIR}" ABSOLUTE) + endif() + mark_as_advanced(GMOCK_INCLUDE_DIR) + endif() + + externalproject_add( + gmock + SOURCE_DIR $ {GMOCK_SRC_DIR} + PREFIX $ {GMOCK_ROOT} + INSTALL_COMMAND "" + LOG_DOWNLOAD ON + LOG_CONFIGURE ON + LOG_BUILD ON + CMAKE_ARGS + -Dgtest_disable_pthreads=$ {MINGW} + $ {GTEST_CMAKE_ARGS} + BINARY_DIR "${GMOCK_BIN_DIR}" + BUILD_BYPRODUCTS + "${GTEST_LIBRARY}" + "${GTEST_MAIN_LIBRARY}" + "${GMOCK_LIBRARY}" + "${GMOCK_MAIN_LIBRARY}" + ) + + add_dependencies(GTest::GTest gmock) + add_dependencies(GTest::Main gmock) + add_dependencies(GMock::GMock gmock) + add_dependencies(GMock::Main gmock) + endif() + endif() + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(GTest DEFAULT_MSG GTEST_LIBRARY GTEST_INCLUDE_DIR GTEST_MAIN_LIBRARY) + find_package_handle_standard_args(GMock DEFAULT_MSG GMOCK_LIBRARY GMOCK_INCLUDE_DIR GMOCK_MAIN_LIBRARY) + + include(CMakeFindDependencyMacro) + find_dependency(Threads) + + set_target_properties(GTest::GTest PROPERTIES + INTERFACE_LINK_LIBRARIES "Threads::Threads" + IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" + IMPORTED_LOCATION "${GTEST_LIBRARY}" + ) + + if(GTEST_INCLUDE_DIR) + set_target_properties(GTest::GTest PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIR}") + endif() + + set_target_properties(GTest::Main PROPERTIES + INTERFACE_LINK_LIBRARIES "GTest::GTest" + IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" + IMPORTED_LOCATION "${GTEST_MAIN_LIBRARY}") + + set_target_properties(GMock::GMock PROPERTIES + INTERFACE_LINK_LIBRARIES "Threads::Threads" + IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" + IMPORTED_LOCATION "${GMOCK_LIBRARY}") + + if(GMOCK_INCLUDE_DIR) + set_target_properties(GMock::GMock PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${GMOCK_INCLUDE_DIR}") + if(GMOCK_VER VERSION_LESS "1.7") +# GMock 1.6 still has GTest as an external link-time dependency, +# so just specify it on the link interface. + set_property(TARGET GMock::GMock APPEND PROPERTY + INTERFACE_LINK_LIBRARIES GTest::GTest) + elseif(GTEST_INCLUDE_DIR) +# GMock 1.7 and beyond doesn't have it as a link-time dependency anymore, +# so merge it's compile-time interface (include dirs) with ours. + set_property(TARGET GMock::GMock APPEND PROPERTY + INTERFACE_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIR}") + endif() + endif() + + set_target_properties(GMock::Main PROPERTIES + INTERFACE_LINK_LIBRARIES "GMock::GMock" + IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" + IMPORTED_LOCATION "${GMOCK_MAIN_LIBRARY}") + + if(GTEST_FOUND) + set(GTEST_INCLUDE_DIRS $ {GTEST_INCLUDE_DIR}) + set(GTEST_LIBRARIES GTest::GTest) + set(GTEST_MAIN_LIBRARIES GTest::Main) + set(GTEST_BOTH_LIBRARIES $ {GTEST_LIBRARIES} $ {GTEST_MAIN_LIBRARIES}) + if(VERBOSE) + message(STATUS "GTest includes: ${GTEST_INCLUDE_DIRS}") + message(STATUS "GTest libs: ${GTEST_BOTH_LIBRARIES}") + endif() + endif() + + if(GMOCK_FOUND) + set(GMOCK_INCLUDE_DIRS $ {GMOCK_INCLUDE_DIR}) + set(GMOCK_LIBRARIES GMock::GMock) + set(GMOCK_MAIN_LIBRARIES GMock::Main) + set(GMOCK_BOTH_LIBRARIES $ {GMOCK_LIBRARIES} $ {GMOCK_MAIN_LIBRARIES}) + if(VERBOSE) + message(STATUS "GMock includes: ${GMOCK_INCLUDE_DIRS}") + message(STATUS "GMock libs: ${GMOCK_BOTH_LIBRARIES}") + endif() + endif() diff --git a/test/CMake/FindValgrind.cmake b/test/CMake/FindValgrind.cmake new file mode 100644 index 0000000..f549154 --- /dev/null +++ b/test/CMake/FindValgrind.cmake @@ -0,0 +1,102 @@ +#.rst: +# FindValgrind +# ------- +# +# The module defines the following variables: +# +# ``VALGRIND_EXECUTABLE`` +# Path to Valgrind command-line client. +# ``Valgrind_FOUND`` +# True if the Valgrind command-line client was found. +# ``VALGRIND_VERSION_STRING`` +# The version of Valgrind found. +# +# Example usage: +# +# .. code-block:: cmake +# +# find_package(Valgrind) +# if(Valgrind_FOUND) +# message("Valgrind found: ${VALGRIND_EXECUTABLE}") +# endif() + +#============================================================================= +# Copyright (c) 2017 Giel van Schijndel +# +# CMake - Cross Platform Makefile Generator +# 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 names of Kitware, Inc., the Insight Software Consortium, +# nor the names of their 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 +# 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. +# +# ------------------------------------------------------------------------------ +# +# The above copyright and license notice applies to distributions of +# CMake in source and binary form. Some source files contain additional +# notices of original copyright by their contributors; see each source +# for details. Third-party software packages supplied with CMake under +# compatible licenses provide their own copyright notices documented in +# corresponding subdirectories. +# +# ------------------------------------------------------------------------------ +# +# CMake was initially developed by Kitware with the following sponsorship: +# +# * National Library of Medicine at the National Institutes of Health +# as part of the Insight Segmentation and Registration Toolkit (ITK). +# +# * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel +# Visualization Initiative. +# +# * National Alliance for Medical Image Computing (NAMIC) is funded by the +# National Institutes of Health through the NIH Roadmap for Medical Research, +# Grant U54 EB005149. +# +# * Kitware, Inc. +#============================================================================= + +find_program(VALGRIND_EXECUTABLE + NAMES valgrind + DOC "Valgrind command line executable" + ) +mark_as_advanced(VALGRIND_EXECUTABLE) + +if(VALGRIND_EXECUTABLE) + execute_process(COMMAND $ {VALGRIND_EXECUTABLE} --version + OUTPUT_VARIABLE VALGRIND_VERSION_STRING + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (VALGRIND_VERSION_STRING MATCHES "^valgrind-[0-9]") + string(REPLACE "valgrind-" "" VALGRIND_VERSION_STRING "${VALGRIND_VERSION_STRING}") + endif() + endif() + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Valgrind + REQUIRED_VARS VALGRIND_EXECUTABLE + VERSION_VAR VALGRIND_VERSION_STRING) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..a7a05bc --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,33 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +PROJECT(RunTest) + +SET(CMAKE_BUILD_TYPE "Debug") +SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb -L /lib64 -l pthread") +SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall") +SET(Boost_USE_STATIC_RUNTIME OFF) +SET(CUKE_CORE_BOOST_LIBS thread system regex date_time program_options filesystem) +SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" $ {CMAKE_MODULE_PATH}) + +IF(NOT CUKE_DISABLE_BOOST_TEST) +# "An external test runner utility is required to link with dynamic library" (Boost User's Guide) + SET(Boost_USE_STATIC_LIBS OFF) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBOOST_TEST_DYN_LINK") + FIND_PACKAGE(Boost ${BOOST_MIN_VERSION} COMPONENTS unit_test_framework) +ENDIF() + +IF(CUKE_USE_STATIC_BOOST) + SET(Boost_USE_STATIC_LIBS ON) + FIND_PACKAGE(Boost ${BOOST_MIN_VERSION} COMPONENTS ${CUKE_CORE_BOOST_LIBS} REQUIRED) + IF(NOT MSVC) + FIND_PACKAGE(Threads) + SET(CUKE_EXTRA_LIBRARIES ${CUKE_EXTRA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + ENDIF() +ELSE() + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBOOST_ALL_DYN_LINK") + SET(Boost_USE_STATIC_LIBS OFF) + FIND_PACKAGE(Boost ${BOOST_MIN_VERSION} COMPONENTS ${CUKE_CORE_BOOST_LIBS} REQUIRED) +ENDIF() + +ADD_SUBDIRECTORY(c_style_tests) +ADD_SUBDIRECTORY(cpp_style_tests) diff --git a/test/c_style_tests/CMakeLists.txt b/test/c_style_tests/CMakeLists.txt new file mode 100644 index 0000000..15a13f2 --- /dev/null +++ b/test/c_style_tests/CMakeLists.txt @@ -0,0 +1,15 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) +SET(CUKE_EXTRA_LIBRARIES ${CUKE_EXTRA_LIBRARIES} ${Boost_THREAD_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_REGEX_LIBRARY} ${Boost_DATE_TIME_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_FILESYSTEM_LIBRARY}) +SET(SRC_LIST RunTestCStyleAPI.cpp) +SET(LIBRARYS_MY /usr/local/lib/libqingstor.so ) +SET(LIBRARYS + /usr/local/lib/libgtest.a + /usr/local/lib/libgmock.a + /usr/local/lib/libcucumber-cpp.a + ) + +ADD_EXECUTABLE(RunTestCStyleAPI ${SRC_LIST}) + +TARGET_LINK_LIBRARIES(RunTestCStyleAPI ${LIBRARYS} ${LIBRARYS_MY} ${Boost_LIBRARIES}) diff --git a/test/c_style_tests/CTestBucket.cpp b/test/c_style_tests/CTestBucket.cpp new file mode 100644 index 0000000..c0ba068 --- /dev/null +++ b/test/c_style_tests/CTestBucket.cpp @@ -0,0 +1,340 @@ +// Scenario: need to use bucket +// When initialize the bucket +// Then the bucket is initialized + +WHEN("^initialize the bucket$") +{ + init_test_config(); +} + +THEN("^the bucket is initialized$") +{ + EXPECT_EQ(NULL, NULL); +} + +////////////////////////// +///// # PUT Bucket ///// +////////////////////////// +/* +Scenario: create the bucket +When put bucket +Then put bucket status code is 201 +*/ +WHEN("^put bucket$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + qs_put_bucket_input_t input; + init_put_bucket_input(&input); + ScenarioScope contextOutput; + QsError err = qs_put_bucket(&input, &(*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + } + qs_release_service(context_hdl); +} + +THEN("^put bucket status code is (\\d+)$") +{ + ScenarioScope contextOutput; + release_put_bucket_output(&(*contextOutput)); + EXPECT_EQ(NULL, NULL); +} + +/* +Scenario: create the same bucket again +When put same bucket again +Then put same bucket again status code is 409 +*/ +WHEN("^put same bucket again$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + qs_put_bucket_input_t input; + init_put_bucket_input(&input); + ScenarioScope contextOutput; + QsError err = qs_put_bucket(&input, &(*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + // print sth + } + qs_release_service(context_hdl); +} + +THEN("^put same bucket again status code is (\\d+)$") +{ + REGEX_PARAM(int, expected); + ScenarioScope contextOutput; + release_put_bucket_output(&(*contextOutput)); + EXPECT_EQ(expected, (int)contextOutput->response_code); +} + +//////////////////////////////////////// +///// # GET Bucket(List Objects) ///// +//////////////////////////////////////// +/* +Scenario: list objects in the bucket + When list objects + Then list objects status code is 200 + And list objects keys count is 0 +*/ + +WHEN("^list objects$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + ScenarioScope contextOutput; + qs_list_objects_input_t input; + init_list_objects_input(&input); + QsError err = qs_list_objects(&input, &(*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + } + qs_release_service(context_hdl); +} + +THEN("^list objects status code is (\\d+)$") +{ + REGEX_PARAM(int, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->response_code); +} + +THEN("^list objects keys count is (\\d+)$") +{ + REGEX_PARAM(int, expected); + ScenarioScope contextOutput; + qs_list_t *keys = contextOutput->keys; + int count = 0; + qs_key_item_t *pos; + qs_list_for_each_entry(qs_key_item_t, pos, keys) + { + count++; + } + release_list_objects_output(&(*contextOutput)); + EXPECT_EQ(expected, count); +} + +/////////////////////////// +///// # Head Bucket ///// +/////////////////////////// +/* +Scenario: head the bucket + When head bucket + Then head bucket status code is 200 +*/ +WHEN("^head bucket$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + qs_head_bucket_input_t input; + ScenarioScope contextOutput; + init_head_bucket_input(&input); + QsError err = qs_head_bucket(&input, &(*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR == err) + { + // print sth + } + qs_release_service(context_hdl); +} + +THEN("^head bucket status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + release_head_bucket_output(&(*contextOutput)); + EXPECT_EQ(expected, (int)contextOutput->response_code); +} + +/////////////////////////////////////// +///// # Delete Multiple Objects ///// +/////////////////////////////////////// +/* +Scenario : delete multiple objects in the bucket + When delete multiple objects : + """ + { + "quiet": false, + "objects" : [ + { + "key": "object_0" + }, + { + "key": "object_1" + }, + { + "key": "object_2" + } + ] + } + """ + Then delete multiple objects code is 200 +*/ +WHEN("^delete multiple objects:$") +{ + // do nothing + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + qs_delete_multiple_objects_input_t input; + init_delete_multiple_objects_input(&input); + ScenarioScope contextOutput; + QsError err = qs_delete_multiple_objects(&input, &(*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR == err) + { + // print sth + } + qs_release_service(context_hdl); +} + +THEN("^delete multiple objects code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + release_delete_multiple_objects_output(&(*contextOutput)); + EXPECT_EQ(expected, expected); +} + +///////////////////////////////////// +///// # GET Bucket Statistics ///// +///////////////////////////////////// +/* +Scenario : get statistics of the bucket + When get bucket statistics + Then get bucket statistics status code is 200 + And get bucket statistics status is "active" +*/ +WHEN("^get bucket statistics$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + qs_get_bucket_statistics_input_t input; + init_get_bucket_statistics_input(&input); + ScenarioScope contextOutput; + QsError err = qs_get_bucket_statistics(&input, &(*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR == err) + { + // print sth + } + qs_release_service(context_hdl); +} + +THEN("^get bucket statistics status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->response_code); +} + +THEN("get bucket statistics status is \"([^\"]*)\"$") +{ + REGEX_PARAM(std::string, expected); + ScenarioScope contextOutput; + std::string status = contextOutput->status; + release_get_bucket_statistics_output(&(*contextOutput)); + EXPECT_EQ(expected, status); +} + +///////////////////////////// +///// # DELETE Bucket ///// +///////////////////////////// +/* +Scenario : delete the bucket + When delete bucket + Then delete bucket status code is 204 +*/ +WHEN("^delete bucket$") +{ + // do nothing +} + +THEN("^delete bucket status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + EXPECT_EQ(NULL, NULL); +} + +////////////////////////////////////// +///// # List Multipart Uploads ///// +////////////////////////////////////// +/* +Scenario : list multipart uploads + Given an object created by initiate multipart upload + When list multipart uploads + Then list multipart uploads count is 1 +*/ + +GIVEN("^an object created by initiate multipart upload$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + ScenarioScope contextGiven; + contextGiven->objectKey = (char *)"testInitMultipartUpload.txt"; + qs_initiate_multipart_upload_input_t input; + ScenarioScope contextOutput; + init_initiate_multipart_upload_input(&input); + QsError err = qs_initiate_multipart_upload((char *)contextGiven->objectKey.c_str(), &input, &(*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR == err && contextOutput->response_code == 200) + { + contextGiven->uploadID = contextOutput->upload_id; + } + release_initiate_multipart_upload_output(&(*contextOutput)); + qs_upload_multipart_input_t multipartInput; + qs_upload_multipart_output_t multipartOutput; + init_upload_multipart_input(&multipartInput); + printf(" |thi is a Part 3| "); + long length = strlen(" |thi is a Part 3| "); + int part_number = strlen(" |thi is a Part 3| "); + multipartInput.bodybuf = (char *)malloc(length); + memcpy(multipartInput.bodybuf, " |thi is a Part 3| ", length); + multipartInput.content_length = &length; + multipartInput.part_number = &part_number; + multipartInput.upload_id = (char *)contextGiven->uploadID.c_str(); + multipartInput.bufLength = &length; + err = qs_upload_multipart((char *)contextGiven->objectKey.c_str(), &multipartInput, &multipartOutput, context_hdl); + if (QS_ERR_NO_ERROR == err) + { + } + release_upload_multipart_output(&multipartOutput); + if(multipartInput.bodybuf && multipartInput.content_length) + { + free(multipartInput.bodybuf); + } + qs_release_service(context_hdl); +} + +WHEN("^list multipart uploads$") +{ + ScenarioScope contextGiven; + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + qs_list_multipart_uploads_input_t input; + ScenarioScope contextOutput; + init_list_multipart_uploads_input(&input); + QsError err = qs_list_multipart_uploads(&input, &(*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR == err) + { + // print sth + } + qs_release_service(context_hdl); +} + +THEN("^list multipart uploads count is (\\d+)$") +{ + REGEX_PARAM(int, expected); + ScenarioScope contextOutput; + int count = 0; + qs_uploads_item_t *pos; + if(contextOutput->uploads) + { + qs_list_for_each_entry(qs_uploads_item_t, pos, contextOutput->uploads) + { + count++; + } + } + release_list_multipart_uploads_output(&(*contextOutput)); + // clean env. + ScenarioScope contextGiven; + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + qs_delete_object_input_t input; + qs_delete_object_output_t output; + init_delete_object_input(&input); + QsError err = qs_delete_object((char *)contextGiven->objectKey.c_str(), &input, &output, context_hdl); + if (QS_ERR_NO_ERROR != err) + { + // print sth + } + qs_release_service(context_hdl); + EXPECT_EQ(expected, count); +} \ No newline at end of file diff --git a/test/c_style_tests/CTestBucketACL.cpp b/test/c_style_tests/CTestBucketACL.cpp new file mode 100644 index 0000000..95a24a0 --- /dev/null +++ b/test/c_style_tests/CTestBucketACL.cpp @@ -0,0 +1,106 @@ +//Feature: the bucket ACL feature + +////////////////////////////// +///// # PUT Bucket ACL ///// +////////////////////////////// + +//Scenario: set the bucket ACL +//When put bucket ACL: +// """ +// { +// "acl": [ +// { +// "grantee": { +// "type": "group", +// "name" : "QS_ALL_USERS" +// }, +// "permission" : "FULL_CONTROL" +// } +// ] +// } +// """ +//Then put bucket ACL status code is 200 +WHEN("^put bucket ACL:$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + qs_put_bucket_acl_input_t input; + ScenarioScope contextOutput; + init_put_bucket_acl_input(&input); + qs_acl_t acl; + qs_grantee_t grantee; + init_acl(&acl); + init_grantee(&grantee); + grantee.type = (char *)"group"; + grantee.name = (char *)"QS_ALL_USERS"; + acl.grantee = &grantee; + acl.permission = (char *)"FULL_CONTROL"; + qs_acl_item_t acl_item; + acl_item.content = &acl; + qs_list_t acllist; + input.acl = &acllist; + qs_list_init(input.acl); + qs_list_append(&acl_item.node, input.acl); + QsError err = qs_put_bucket_acl(&input, &(*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + // print sth + } + qs_release_service(context_hdl); +} + +THEN("^put bucket ACL status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + release_put_bucket_acl_output(&(*contextOutput)); + EXPECT_EQ(expected, (int)contextOutput->response_code); +} + +////////////////////////////// +///// # GET Bucket ACL ///// +////////////////////////////// +/* +Scenario : get ACL of the bucket +When get bucket ACL +Then get bucket ACL status code is 200 +And get bucket ACL should have grantee name "QS_ALL_USERS" +*/ +WHEN("^get bucket ACL$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + qs_get_bucket_acl_input_t input; + ScenarioScope contextOutput; + init_get_bucket_acl_input(&input); + QsError err = qs_get_bucket_acl(&input, &(*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + // print sth + } + qs_release_service(context_hdl); +} + +THEN("^get bucket ACL status code is (\\d+)$") +{ + REGEX_PARAM(int, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->response_code); +} + +THEN("^get bucket ACL should have grantee name \"([^\"]*)\"$") +{ + REGEX_PARAM(std::string, expected); + ScenarioScope contextOutput; + std::string granteeName = (char *)""; + qs_acl_item_t *item; + qs_list_t acl; + qs_list_init(&acl); + qs_list_for_each_entry(qs_acl_item_t, item, contextOutput->acl) + { + if (item->content && item->content->grantee && item->content->grantee->name) + { + granteeName = item->content->grantee->name; + } + } + release_get_bucket_acl_output(&(*contextOutput)); + EXPECT_EQ(expected, granteeName); +} \ No newline at end of file diff --git a/test/c_style_tests/CTestBucketCORS.cpp b/test/c_style_tests/CTestBucketCORS.cpp new file mode 100644 index 0000000..7a9921e --- /dev/null +++ b/test/c_style_tests/CTestBucketCORS.cpp @@ -0,0 +1,210 @@ +//////////Feature: the bucket CORS feature + +/////////////////////////////// +///// # PUT Bucket CORS ///// +/////////////////////////////// +//Scenario : set the bucket CORS +// When put bucket CORS : +// """ +// { +// "cors_rules": [ +// { +// "allowed_origin": "http://*.qingcloud.com", +// "allowed_methods" : [ +// "PUT", +// "GET", +// "DELETE", +// "POST" +// ], +// "allowed_headers": [ +// "X-QS-Date", +// "Content-Type", +// "Content-MD5", +// "Authorization" +// ], +// "max_age_seconds": 200, +// "expose_headers" : [ +// "X-QS-Date" +// ] +// }, +// { +// "allowed_origin": "http://*.example.com", +// "allowed_methods" : [ +// "PUT", +// "GET", +// "DELETE", +// "POST" +// ], +// "allowed_headers": [ +// "*" +// ], +// "max_age_seconds" : 400 +// } +// ] +// } +// """ +// Then put bucket CORS status code is 200 +WHEN ("^put bucket CORS:$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + ScenarioScope contextOutput; + qs_put_bucket_cors_input_t input; + init_put_bucket_cors_input (&input); + qs_cors_rule_item_t rules_item1, rules_item2; + //qs_cors_rule_t rule1,rule2; + qs_cors_rule_t content1, content2; + init_cors_rule (&content1); + init_cors_rule (&content2); + qs_list_t allowed_headers_1; + qs_list_t allowed_headers_2; + qs_list_t expose_headers_1; + qs_list_t expose_headers_2; + qs_list_t allowed_methods_1; + qs_list_t allowed_methods_2; + qs_list_init (&allowed_headers_1); + qs_list_init (&allowed_headers_2); + qs_list_init (&expose_headers_1); + qs_list_init (&expose_headers_2); + qs_list_init (&allowed_methods_1); + qs_list_init (&allowed_methods_2); + content1.allowed_headers = &allowed_headers_1; + content1.expose_headers = &expose_headers_1; + content1.allowed_methods = &allowed_methods_1; + content2.allowed_headers = &allowed_headers_2; + content2.expose_headers = &expose_headers_2; + content2.allowed_methods = &allowed_methods_2; + rules_item1.content = &content1; + rules_item2.content = &content2; + qs_cors_rule_allowed_methods_item_t allowed_method_item1[4]; + allowed_method_item1[0].content = (char *)"PUT"; + allowed_method_item1[1].content = (char *)"GET"; + allowed_method_item1[2].content = (char *)"DELETE"; + allowed_method_item1[3].content = (char *)"POST"; + qs_cors_rule_allowed_methods_item_t allowed_method_item2[4]; + allowed_method_item2[0].content = (char *)"PUT"; + allowed_method_item2[1].content = (char *)"GET"; + allowed_method_item2[2].content = (char *)"DELETE"; + allowed_method_item2[3].content = (char *)"POST"; + qs_cors_rule_allowed_headers_item_t allowed_headers_item1; + allowed_headers_item1.content = (char *)"*"; + qs_cors_rule_allowed_headers_item_t allowed_headers_item2; + allowed_headers_item2.content = (char *)"*"; + qs_cors_rule_expose_headers_item_t expose_headers_item1; + expose_headers_item1.content = (char *)"X-QS-Date"; + qs_cors_rule_expose_headers_item_t expose_headers_item2; + expose_headers_item2.content = (char *)"X-QS-Date"; + qs_list_init (rules_item1.content->allowed_methods); + qs_list_append (&allowed_method_item1[0].node, rules_item1.content->allowed_methods); + qs_list_append (&allowed_method_item1[1].node, rules_item1.content->allowed_methods); + qs_list_append (&allowed_method_item1[2].node, rules_item1.content->allowed_methods); + qs_list_append (&allowed_method_item1[3].node, rules_item1.content->allowed_methods); + qs_list_append (&allowed_headers_item1.node, rules_item1.content->allowed_headers); + qs_list_append (&expose_headers_item1.node, rules_item1.content->expose_headers); + rules_item1.content->allowed_origin = (char *)"http://*.qingcloud.com"; + int max_age_seconds = 200; + rules_item1.content->max_age_seconds = &max_age_seconds; + qs_list_append (&allowed_method_item2[0].node, rules_item2.content->allowed_methods); + qs_list_append (&allowed_method_item2[1].node, rules_item2.content->allowed_methods); + qs_list_append (&allowed_method_item2[2].node, rules_item2.content->allowed_methods); + qs_list_append (&allowed_method_item2[3].node, rules_item2.content->allowed_methods); + qs_list_append (&allowed_headers_item2.node, rules_item2.content->allowed_headers); + qs_list_append (&expose_headers_item2.node, rules_item2.content->expose_headers); + rules_item2.content->allowed_origin = (char *)"http://*.example.com"; + max_age_seconds = 400; + rules_item2.content->max_age_seconds = &max_age_seconds; + qs_list_t cors_rules; + qs_list_init (&cors_rules); + input.cors_rules = &cors_rules; + qs_list_append (&rules_item1.node, input.cors_rules); + qs_list_append (&rules_item2.node, input.cors_rules); + QsError err = qs_put_bucket_cors (&input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + // print sth + } + qs_release_service(context_hdl); +} + +THEN ("^put bucket CORS status code is (\\d+)$") +{ + REGEX_PARAM (double, expected); + ScenarioScope contextOutput; + release_put_bucket_cors_output (& (*contextOutput)); + EXPECT_EQ (expected, (int)contextOutput->response_code); +} + +/////////////////////////////// +///// # GET Bucket CORS ///// +/////////////////////////////// +/* +Scenario : get CORS of the bucket + When get bucket CORS + Then get bucket CORS status code is 200 + And get bucket CORS should have allowed origin "http://\*.qingcloud.com" +*/ +WHEN ("^get bucket CORS$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + qs_get_bucket_cors_input_t input; + ScenarioScope contextOutput; + init_get_bucket_cors_input (&input); + QsError err = qs_get_bucket_cors (&input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + } + qs_release_service(context_hdl); +} + +THEN ("^get bucket CORS status code is (\\d+)$") +{ + REGEX_PARAM (double, expected); + ScenarioScope contextOutput; + EXPECT_EQ (expected, (int)contextOutput->response_code); +} + +THEN ("^get bucket CORS should have allowed origin \"([^\"]*)\"$") +{ + REGEX_PARAM (std::string, expected); + ScenarioScope contextOutput; + std::string allowedOrigin; + int count = 0; + qs_cors_rule_item_t *pos; + qs_list_for_each_entry (qs_cors_rule_item_t, pos, contextOutput->cors_rules) + count++; + if (count) + { + qs_cors_rule_item_t *corsRule = qs_list_get_first (contextOutput->cors_rules, qs_cors_rule_item_t); + allowedOrigin = corsRule->content->allowed_origin; + } + release_get_bucket_cors_output (& (*contextOutput)); + EXPECT_EQ (expected, allowedOrigin); +} + +////////////////////////////////// +///// # DELETE Bucket CORS ///// +////////////////////////////////// +/* +Scenario : delete CORS of the bucket + When delete bucket CORS + Then delete bucket CORS status code is 204 +*/ +WHEN ("^delete bucket CORS$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + qs_delete_bucket_cors_input_t input; + ScenarioScope contextOutput; + init_delete_bucket_cors_input (&input); + QsError err = qs_delete_bucket_cors (&input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + } + qs_release_service(context_hdl); +} + +THEN ("^delete bucket CORS status code is (\\d+)$") +{ + REGEX_PARAM (double, expected); + ScenarioScope contextOutput; + release_delete_bucket_cors_output (& (*contextOutput)); + EXPECT_EQ (expected, (int)contextOutput->response_code); +} diff --git a/test/c_style_tests/CTestBucketExternalMirror.cpp b/test/c_style_tests/CTestBucketExternalMirror.cpp new file mode 100644 index 0000000..b1b111c --- /dev/null +++ b/test/c_style_tests/CTestBucketExternalMirror.cpp @@ -0,0 +1,107 @@ +///// Feature: the bucket external mirror feature + +//////////////////////////////////////////// +///// # PUT Bucket External Mirror ///// +//////////////////////////////////////////// +/* +Scenario : set the bucket external mirror + When put bucket external mirror : + """ + { + "source_site": "https://example.com/something/" + } + """ + Then put bucket external mirror status code is 200 +*/ +WHEN ("^put bucket external mirror:$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + qs_put_bucket_external_mirror_input_t input; + ScenarioScope contextOutput; + init_put_bucket_external_mirror_input (&input); + input.source_site = (char *)"https://example.com/something/"; + QsError err = qs_put_bucket_external_mirror (&input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + } + qs_release_service(context_hdl); +} + +THEN ("^put bucket external mirror status code is (\\d+)$") +{ + REGEX_PARAM (double, expected); + ScenarioScope contextOutput; + release_put_bucket_external_mirror_output (& (*contextOutput)); + EXPECT_EQ (expected, (int)contextOutput->response_code); +} + +//////////////////////////////////////////// +///// # GET Bucket External Mirror ///// +//////////////////////////////////////////// +/* +Scenario : get external mirror of the bucket + When get bucket external mirror + Then get bucket external mirror status code is 200 + And get bucket external mirror should have source_site "https://example.com/something/" +*/ +WHEN ("^get bucket external mirror$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + qs_get_bucket_external_mirror_input_t input; + ScenarioScope contextOutput; + init_get_bucket_external_mirror_input (&input); + QsError err = qs_get_bucket_external_mirror (&input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + } + qs_release_service(context_hdl); +} + +THEN ("^get bucket external mirror status code is (\\d+)$") +{ + REGEX_PARAM (double, expected); + ScenarioScope contextOutput; + EXPECT_EQ (expected, (int)contextOutput->response_code); +} + +THEN ("^get bucket external mirror should have source_site \"([^\"]*)\"$") +{ + REGEX_PARAM (std::string, expected); + ScenarioScope contextOutput; + std::string sourceSite = (char *)""; + if (contextOutput->source_site) + { + sourceSite = contextOutput->source_site; + } + release_get_bucket_external_mirror_output (& (*contextOutput)); + EXPECT_EQ (expected, sourceSite); +} + +/////////////////////////////////////////////// +///// # DELETE Bucket External Mirror ///// +/////////////////////////////////////////////// +/* +Scenario : delete external mirror of the bucket + When delete bucket external mirror + Then delete bucket external mirror status code is 204 +*/ +WHEN ("^delete bucket external mirror$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + qs_delete_bucket_external_mirror_input_t input; + ScenarioScope contextOutput; + init_delete_bucket_external_mirror_input (&input); + QsError err = qs_delete_bucket_external_mirror (&input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + } + qs_release_service(context_hdl); +} + +THEN ("^delete bucket external mirror status code is (\\d+)$") +{ + REGEX_PARAM (double, expected); + ScenarioScope contextOutput; + release_delete_bucket_cors_output (& (*contextOutput)); + EXPECT_EQ (expected, (int)contextOutput->response_code); +} \ No newline at end of file diff --git a/test/c_style_tests/CTestBucketPolicy.cpp b/test/c_style_tests/CTestBucketPolicy.cpp new file mode 100644 index 0000000..d738d83 --- /dev/null +++ b/test/c_style_tests/CTestBucketPolicy.cpp @@ -0,0 +1,201 @@ +//// Feature: the bucket policy feature + +////////////////////////////////// +///// # PUT Bucket policy ///// +////////////////////////////////// +/* +Scenario : set the bucket policy + # Notice : Please set statement resource manually + When put bucket policy : + """ + { + "statement": [ + { + "id": "allow certain site to get objects", + "user" : [ + "*" + ], + "action" : [ + "get_object" + ], + "effect" : "allow", + "resource" : [], + "condition" : { + "string_like": { + "Referer": [ + "*.example1.com", + "*.example2.com" + ] + }, + "ip_address": { + "source_ip": [ + "172.16.0.0/24", + "172.16.1.1/32" + ] + } + } + } + ] + } + """ + Then put bucket policy status code is 200 +*/ +WHEN ("^put bucket policy:$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + ScenarioScope contextOutput; + qs_put_bucket_policy_input_t input; + init_put_bucket_policy_input (&input); + qs_list_t statement_list; + qs_statement_item_t statement_item; + qs_statement_t statement; + init_statement (&statement); + qs_list_t userlist; + qs_list_t actionlist; + qs_condition_t condition; + init_condition (&condition); + // user + qs_list_init (&userlist); + qs_string_item_t user_item; + user_item.content = (char *)"*"; + qs_list_append (&user_item.node, &userlist); + // action + qs_list_init (&actionlist); + qs_string_item_t action_item; + action_item.content = (char *)"list_objects"; //"get_object"; + qs_list_append (&action_item.node, &actionlist); + /* + // resource + qs_list_t resource_list; + qs_list_init(&resource_list); + qs_string_item_t user_item; + user_item.content = (char *)"*"; + qs_list_append(&user_item.node, &userlist); + */ + // condition + qs_string_like_t string_like; + qs_list_t referer_list; + qs_list_init (&referer_list); + qs_string_item_t referer_item_1, referer_item_2; + referer_item_1.content = (char *)"*.example1.com"; + referer_item_2.content = (char *)"*.example2.com"; + qs_list_append (&referer_item_1.node, &referer_list); + qs_list_append (&referer_item_2.node, &referer_list); + string_like.referer = &referer_list; + ///////////////// + qs_ip_address_t ip_address; + qs_list_t source_ip_list; + qs_list_init (&source_ip_list); + qs_string_item_t source_ip_item_1, source_ip_item_2; + source_ip_item_1.content = (char *)"172.16.0.0/24"; + source_ip_item_2.content = (char *)"172.16.1.1/32"; + qs_list_append (&source_ip_item_1.node, &source_ip_list); + qs_list_append (&source_ip_item_2.node, &source_ip_list); + ip_address.source_ip = &source_ip_list; + condition.string_like = &string_like; + condition.ip_address = &ip_address; + // statement + statement.id = (char *)"allow certain site to get objects"; + statement.user = &userlist; + statement.effect = (char *)"allow"; + statement.action = &actionlist; + statement.condition = &condition; + // call api + qs_list_init (&statement_list); + statement_item.content = &statement; + qs_list_append (&statement_item.node, &statement_list); + input.statement = &statement_list; + QsError err = qs_put_bucket_policy (&input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + } + qs_release_service(context_hdl); +} + +THEN ("^put bucket policy status code is (\\d+)$") +{ + REGEX_PARAM (double, expected); + ScenarioScope contextOutput; + release_put_bucket_policy_output (& (*contextOutput)); + EXPECT_EQ (expected, (int)contextOutput->response_code); +} + +////////////////////////////////// +///// # GET Bucket policy ///// +////////////////////////////////// +/* +Scenario : get policy of the bucket + When get bucket policy + Then get bucket policy status code is 200 + And get bucket policy should have Referer "*.example1.com" +*/ +WHEN ("^get bucket policy$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + qs_get_bucket_policy_input_t input; + ScenarioScope contextOutput; + init_get_bucket_policy_input (&input); + QsError err = qs_get_bucket_policy (&input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + } + qs_release_service(context_hdl); +} + +THEN ("^get bucket policy status code is (\\d+)$") +{ + REGEX_PARAM (double, expected); + ScenarioScope contextOutput; + EXPECT_EQ (expected, (int)contextOutput->response_code); +} + +THEN ("^get bucket policy should have Referer \"([^\"]*)\"$") +{ + REGEX_PARAM (std::string, expected); + ScenarioScope contextOutput; + char *referer = (char *)""; + if (!qs_is_list_empty (contextOutput->statement)) + { + qs_statement_item_t *statement_item = qs_list_get_first (contextOutput->statement, qs_statement_item_t); + if (statement_item->content->condition && statement_item->content->condition->string_like && !qs_is_list_empty (statement_item->content->condition->string_like->referer)) + { + qs_string_like_referer_item_t *referer_item = qs_list_get_first (statement_item->content->condition->string_like->referer, qs_string_like_referer_item_t); + if (referer_item) + { + referer = referer_item->content; + } + } + } + std::string ref = referer; + release_get_bucket_policy_output (& (*contextOutput)); + EXPECT_EQ (expected.c_str(), ref); +} + +//////////////////////////////////// +///// # DELETE Bucket policy ///// +//////////////////////////////////// +/* +Scenario : delete policy of the bucket + When delete bucket policy + Then delete bucket policy status code is 204 +*/ +WHEN ("^delete bucket policy$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + qs_delete_bucket_policy_input_t input; + ScenarioScope contextOutput; + init_delete_bucket_policy_input (&input); + QsError err = qs_delete_bucket_policy (&input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + } + qs_release_service(context_hdl); +} + +THEN ("^delete bucket policy status code is (\\d+)$") +{ + REGEX_PARAM (int, expected); + ScenarioScope contextOutput; + release_delete_bucket_policy_output (& (*contextOutput)); + EXPECT_EQ (expected, (int)contextOutput->response_code); +} diff --git a/test/c_style_tests/CTestObject.cpp b/test/c_style_tests/CTestObject.cpp new file mode 100644 index 0000000..4281712 --- /dev/null +++ b/test/c_style_tests/CTestObject.cpp @@ -0,0 +1,336 @@ +//// Feature: the object feature + +// Scenario Outline : +// # PUT Object +// When put object with key "" +// Then put object status code is 201 +WHEN ("^put object with key \"(.{1,})\"$") +{ + init_test_config(); + typedef char *String; + REGEX_PARAM (std::string, objectKey); + ScenarioScope contextObjectTest; + contextObjectTest->bucketName = strBucketName; + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + qs_put_object_input_t input; + ScenarioScope contextOutput; + init_put_object_input (&input); + long length = strlen ("this is a test"); + input.bodybuf = (String)malloc (length + 1); + memset(input.bodybuf, 0, length + 1); + memcpy (input.bodybuf, "this is a test", length); + input.content_length = &length; + input.bufLength = &length; + char * object_key = (char *)malloc(objectKey.length() + 1); + memset(object_key,0,objectKey.length() +1 ); + strncpy(object_key, objectKey.c_str() , objectKey.length()); + QsError err = qs_put_object (object_key, &input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + } + if(input.bodybuf && input.bufLength) + { + free(input.bodybuf); + } + free(object_key); + qs_release_service(context_hdl); +} + +THEN ("^put object status code is (\\d+)$") +{ + REGEX_PARAM (int, expected); + ScenarioScope contextOutput; + release_put_object_output (& (*contextOutput)); + EXPECT_EQ (expected, (int)contextOutput->response_code); +} + +//# Copy Object +//When copy object with key "" +//Then copy object status code is 201 +WHEN ("^copy object with key \"(.{1,})\"$") +{ + REGEX_PARAM (std::string, objectkeyFromSource); + std::string objectkeyTopPut = objectkeyFromSource + "_copy"; + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + ScenarioScope contextObjectTest; + std::string copySource = (char *)"/" + contextObjectTest->bucketName + "/" + objectkeyFromSource; + qs_put_object_input_t input; + ScenarioScope contextOutput; + init_put_object_input (&input); + input.x_qs_copy_source = (char *)copySource.c_str(); + long content_length = 0; + input.content_length = &content_length; + char * object_key = (char *)malloc(objectkeyTopPut.length() + 1); + memset(object_key,0,objectkeyTopPut.length() + 1); + strncpy(object_key, objectkeyTopPut.c_str() , objectkeyTopPut.length()); + QsError err = qs_put_object (object_key, &input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + // print sth + } + free(object_key); + qs_release_service(context_hdl); +} + +THEN ("^copy object status code is (\\d+)$") +{ + REGEX_PARAM (int, expected); + ScenarioScope contextOutput; + release_put_object_output (& (*contextOutput)); + EXPECT_EQ (expected, (int)contextOutput->response_code); +} + +//# Move Object +//When move object with key "" +//Then move object status code is 201 +WHEN ("^move object with key \"(.{1,})\"$") +{ + REGEX_PARAM (std::string, objectkey); + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + std::string objectkeySrc = objectkey + "_copy"; + std::string objectkeyDest = objectkey + "_move"; + ScenarioScope contextObjectTest; + std::string moveSource = (char *)"/" + contextObjectTest->bucketName + "/" + objectkeySrc; + qs_put_object_input_t input; + ScenarioScope contextOutput; + init_put_object_input (&input); + input.x_qs_move_source = (char *)moveSource.c_str(); + long content_length = 0; + input.content_length = &content_length; + char * object_key = (char *)malloc(objectkey.length() + 1); + memset(object_key,0,objectkey.length() + 1); + strncpy(object_key, objectkey.c_str() , objectkey.length()); + QsError err = qs_put_object (object_key, &input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + // print sth + } + free(object_key); + qs_release_service(context_hdl); +} + +THEN ("^move object status code is (\\d+)$") +{ + REGEX_PARAM (int, expected); + ScenarioScope contextOutput; + release_put_object_output (& (*contextOutput)); + EXPECT_EQ (expected, (int)contextOutput->response_code); +} + +//# GET Object +//When get object with key "" +//Then get object status code is 200 +//And get object content length is 1048576 +WHEN ("^get object with key \"(.{1,})\"$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + REGEX_PARAM (std::string, objectkeyToGet); + qs_get_object_input_t input; + ScenarioScope contextOutput; + init_get_object_input (&input); + char * object_key = (char *)malloc(objectkeyToGet.length() + 1); + memset(object_key,0,objectkeyToGet.length()+1); + strncpy(object_key, objectkeyToGet.c_str() , objectkeyToGet.length()); + QsError err = qs_get_object (object_key, &input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + // print sth + } + free(object_key); + qs_release_service(context_hdl); +} + +THEN ("^get object status code is (\\d+)$") +{ + REGEX_PARAM (int, expected); + ScenarioScope contextOutput; + EXPECT_EQ (expected, (int)contextOutput->response_code); +} + +THEN ("^get object content length is (\\d+)$") +{ + REGEX_PARAM (int, expected); + (void)expected; + ScenarioScope contextOutput; + int objectLen = 0; + if (contextOutput->bufLength && contextOutput->bodybuf) + { + objectLen = (int) (*contextOutput->bufLength); + } + int exceptedLen = strlen ("this is a test"); + release_get_object_output (& (*contextOutput)); + EXPECT_EQ (exceptedLen, objectLen); +} + +//# GET Object with Content - Type +//When get object "" with content type "video/mp4; charset=utf8" +//Then get object content type is "video/mp4; charset=utf8" +WHEN ("^get object \"(.{1,})\" with content type \"(.{1,})\"$") +{ + REGEX_PARAM (std::string, objectkey); + ScenarioScope contextObjectTest; +} + +THEN ("^get object content type is \"(.{1,})\"$") +{ + //typedef char* String; + REGEX_PARAM (std::string, expected); + EXPECT_EQ (expected, "video/mp4; charset=utf8"); +} + +//# GET Object with Query Signature +//When get object "" with query signature +//Then get object with query signature content length is 1048576 +WHEN ("^get object \"(.{1,})\" with query signature$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + REGEX_PARAM (std::string, objectkey); + qs_get_object_input_t input; + ScenarioScope contextOutput; + init_get_object_input (&input); + char * object_key = (char *)malloc(objectkey.length() + 1); + memset(object_key,0,objectkey.length() + 1); + strncpy(object_key, objectkey.c_str() , objectkey.length()); + QsError err = qs_get_object (object_key, &input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + // print sth + } + free(object_key); + qs_release_service(context_hdl); +} + +THEN ("^get object with query signature content length is (\\d+)$") +{ + ScenarioScope contextOutput; + int objectLen = 0; + if (contextOutput->bufLength && contextOutput->bodybuf) + { + objectLen = (int) (*contextOutput->bufLength); + } + int exceptedLen = strlen ("this is a test"); + release_get_object_output (& (*contextOutput)); + EXPECT_EQ (exceptedLen, objectLen); +} + +//# Head Object +//When head object with key "" +//Then head object status code is 200 +WHEN ("^head object with key \"(.{1,})\"$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + REGEX_PARAM (std::string, objectkey); + qs_head_object_input_t input; + ScenarioScope contextOutput; + init_head_object_input (&input); + char * object_key = (char *)malloc(objectkey.length() + 1); + memset(object_key,0,objectkey.length() + 1); + strncpy(object_key, objectkey.c_str() , objectkey.length()); + QsError err = qs_head_object (object_key, &input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + // print sth + } + free(object_key); + qs_release_service(context_hdl); +} + +THEN ("^head object status code is (\\d+)$") +{ + REGEX_PARAM (int, expected); + ScenarioScope contextOutput; + release_head_object_output (& (*contextOutput)); + EXPECT_EQ (expected, (int)contextOutput->response_code); +} + +//# Options Object +//When options object "" with method "GET" and origin "qingcloud.com" +//Then options object status code is 200 +WHEN ("^options object \"(.{1,})\" with method \"([^\"]*)\" and origin \"([^\"]*)\"$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + REGEX_PARAM (std::string, objectkey); + qs_options_object_input_t input; + ScenarioScope contextOutput; + init_options_object_input (&input); + input.access_control_request_method = (char *)"GET"; + input.origin = (char *)"qingcloud.com"; + char * object_key = (char *)malloc(objectkey.length() + 1); + memset(object_key,0,objectkey.length() + 1); + strncpy(object_key, objectkey.c_str() , objectkey.length()); + QsError err = qs_options_object (object_key, &input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + // print sth + } + free(object_key); + qs_release_service(context_hdl); +} + +THEN ("^options object status code is (\\d+)$") +{ + REGEX_PARAM (int, expected); + ScenarioScope contextOutput; + release_options_object_output (& (*contextOutput)); + EXPECT_EQ (expected, (int)contextOutput->response_code); +} + +//# DELETE Object +//When delete object with key "" +//Then delete object status code is 204 +//When delete the move object with key "" +//Then delete the move object status code is 204 +WHEN ("^delete object with key \"(.{1,})\"$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + REGEX_PARAM (std::string, objectkey); + qs_delete_object_input_t input; + ScenarioScope contextOutput; + init_delete_object_input (&input); + char * object_key = (char *)malloc(objectkey.length() + 1); + memset(object_key,0,objectkey.length() + 1); + strncpy(object_key, objectkey.c_str() , objectkey.length()); + QsError err = qs_delete_object (object_key, &input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + // print sth + } + free(object_key); + qs_release_service(context_hdl); +} + +THEN ("^delete object status code is (\\d+)$") +{ + REGEX_PARAM (int, expected); + ScenarioScope contextOutput; + release_delete_object_output (& (*contextOutput)); + EXPECT_EQ (expected, (int)contextOutput->response_code); +} + +WHEN ("delete the move object with key \"(.{1,})\"$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + REGEX_PARAM (std::string, objectkey); + std::string objectkeyToDel = objectkey + "_move"; + qs_delete_object_input_t input; + ScenarioScope contextOutput; + init_delete_object_input (&input); + char * object_key = (char *)malloc(objectkey.length() + 1); + memset(object_key,0,objectkey.length() + 1); + strncpy(object_key, objectkey.c_str() , objectkey.length()); + QsError err = qs_delete_object (object_key, &input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + // print sth + } + free(object_key); + qs_release_service(context_hdl); +} + +THEN ("^delete the move object status code is (\\d+)$") +{ + REGEX_PARAM (int, expected); + ScenarioScope contextOutput; + release_delete_object_output (& (*contextOutput)); + EXPECT_EQ (expected, (int)contextOutput->response_code); +} diff --git a/test/c_style_tests/CTestObjectMultipart.cpp b/test/c_style_tests/CTestObjectMultipart.cpp new file mode 100644 index 0000000..f8e08db --- /dev/null +++ b/test/c_style_tests/CTestObjectMultipart.cpp @@ -0,0 +1,284 @@ + +//Scenario Outline : +//# Initiate Multipart Upload +//When initiate multipart upload with key "" +//Then initiate multipart upload status code is 200 +WHEN ("^initiate multipart upload with key \"(.{1,})\"$") +{ + REGEX_PARAM (std::string, objectkey); + ScenarioScope contextMultiPartObjectTest; + contextMultiPartObjectTest->bucketName = (char *)"testmorvenhuang"; + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + contextMultiPartObjectTest->pQsBucket = context_hdl.pQsBucket; + qs_initiate_multipart_upload_input_t input; + ScenarioScope contextOutput; + init_initiate_multipart_upload_input (&input); + QsError err = qs_initiate_multipart_upload ((char *) (objectkey.c_str()), &input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR == err) + { + contextMultiPartObjectTest->uploadID = contextOutput->upload_id; + } + qs_release_service(context_hdl); +} +THEN ("^initiate multipart upload status code is (\\d+)$") +{ + REGEX_PARAM (int, expected); + ScenarioScope contextOutput; + release_initiate_multipart_upload_output (& (*contextOutput)); + EXPECT_EQ (expected, (int)contextOutput->response_code); +} + +//# Upload Multipart +//When upload the first part with key "" +//Then upload the first part status code is 201 +//When upload the second part with key "" +//Then upload the second part status code is 201 +//When upload the third part with key "" +//Then upload the third part status code is 201 +WHEN ("^upload the first part with key \"(.{1,})\"$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + REGEX_PARAM (std::string, objectkey); + ScenarioScope contextMultiPartObjectTest; + qs_upload_multipart_input_t input; + ScenarioScope contextOutput; + init_upload_multipart_input (&input); + //long length = strlen (" |thi is a Part 1| "); + long length = 5 * 1024 * 1024; //fiveMbSize + int part_number = 1; + input.bodybuf = (char *)malloc (length); + memset(input.bodybuf, 0 , length); + input.bufLength = &length; + input.content_length = &length; + input.part_number = &part_number; + input.upload_id = (char *)contextMultiPartObjectTest->uploadID.c_str(); + QsError err = qs_upload_multipart ((char *) (objectkey.c_str()), &input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR == err) + { + // print sth + } + if(input.bodybuf) + { + free(input.bodybuf); + input.bodybuf = NULL; + } + qs_release_service(context_hdl); +} +THEN ("^upload the first part status code is (\\d+)$") +{ + REGEX_PARAM (int, expected); + ScenarioScope contextOutput; + release_upload_multipart_output (& (*contextOutput)); + EXPECT_EQ (expected, (int)contextOutput->response_code); +} + +WHEN ("^upload the second part with key \"(.{1,})\"$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + REGEX_PARAM (std::string, objectkey); + qs_upload_multipart_input_t input; + ScenarioScope contextOutput; + ScenarioScope contextMultiPartObjectTest; + init_upload_multipart_input (&input); + long length = 5 * 1024 * 1024; //fiveMbSize + int part_number = 2; + input.bodybuf = (char *)malloc (length); + memset(input.bodybuf, 0 , length); + input.bufLength = &length; + input.content_length = &length; + input.part_number = &part_number; + input.upload_id = (char *)contextMultiPartObjectTest->uploadID.c_str(); + QsError err = qs_upload_multipart ((char *) (objectkey.c_str()), &input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR == err) + { + // print sth + } + if(input.bodybuf) + { + free(input.bodybuf); + input.bodybuf = NULL; + } + qs_release_service(context_hdl); +} +THEN ("^upload the second part status code is (\\d+)$") +{ + REGEX_PARAM (int, expected); + ScenarioScope contextOutput; + release_upload_multipart_output (& (*contextOutput)); + EXPECT_EQ (expected, (int)contextOutput->response_code); +} +WHEN ("^upload the third part with key \"(.{1,})\"$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + REGEX_PARAM (std::string, objectkey); + qs_upload_multipart_input_t input; + ScenarioScope contextOutput; + ScenarioScope contextMultiPartObjectTest; + init_upload_multipart_input (&input); + long length = 5 * 1024 * 1024; //fiveMbSize + int part_number = 3; + input.bodybuf = (char *)malloc (length); + memset(input.bodybuf, 0 , length); + input.bufLength = &length; + input.content_length = &length; + input.part_number = &part_number; + input.upload_id = (char *)contextMultiPartObjectTest->uploadID.c_str(); + QsError err = qs_upload_multipart ((char *) (objectkey.c_str()), &input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR == err) + { + } + if(input.bodybuf) + { + free(input.bodybuf); + input.bodybuf = NULL; + } + qs_release_service(context_hdl); +} +THEN ("^upload the third part status code is (\\d+)$") +{ + REGEX_PARAM (int, expected); + ScenarioScope contextOutput; + release_upload_multipart_output (& (*contextOutput)); + EXPECT_EQ (expected, (int)contextOutput->response_code); +} + +//# List Multipart +//When list multipart with key "" +//Then list multipart status code is 200 +//And list multipart object parts count is 3 +WHEN ("^list multipart with key \"(.{1,})\"$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + REGEX_PARAM (std::string, objectkey); + ScenarioScope contextMultiPartObjectTest; + qs_list_multipart_input_t input; + ScenarioScope contextOutput; + init_list_multipart_input (&input); + input.upload_id = (char *)contextMultiPartObjectTest->uploadID.c_str(); + QsError err = qs_list_multipart ((char *) (objectkey.c_str()), &input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR == err) + { + // print sth + } + qs_release_service(context_hdl); +} + +THEN ("^list multipart status code is (\\d+)$") +{ + REGEX_PARAM (int, expected); + ScenarioScope contextOutput; + EXPECT_EQ (expected, (int)contextOutput->response_code); +} + +THEN ("^list multipart object parts count is (\\d+)$") +{ + REGEX_PARAM (int, expected); + ScenarioScope contextOutput; + int count = 0; + if (contextOutput->count) + { + count = *contextOutput->count; + } + release_list_multipart_output (& (*contextOutput)); + EXPECT_EQ (expected, count); +} + +//# Complete Multipart Upload +//When complete multipart upload with key "" +//Then complete multipart upload status code is 201 +WHEN ("^complete multipart upload with key \"(.{1,})\"$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + REGEX_PARAM (std::string, objectkey); + ScenarioScope contextMultiPartObjectTest; + qs_complete_multipart_upload_input_t input; + ScenarioScope contextOutput; + init_complete_multipart_upload_input (&input); + qs_list_t object_parts_list; + qs_list_init (&object_parts_list); + qs_object_part_item_t object_parts_item_1, object_parts_item_2, object_parts_item_3; + qs_object_part_t object_parts_1, object_parts_2, object_parts_3; + init_object_part (&object_parts_1); + init_object_part (&object_parts_2); + init_object_part (&object_parts_3); + int part_number_1 = 1; + int part_number_2 = 2; + int part_number_3 = 3; + object_parts_1.part_number = &part_number_1; + object_parts_2.part_number = &part_number_2; + object_parts_3.part_number = &part_number_3; + object_parts_item_1.content = &object_parts_1; + object_parts_item_2.content = &object_parts_2; + object_parts_item_3.content = &object_parts_3; + qs_list_append (&object_parts_item_1.node, &object_parts_list); + qs_list_append (&object_parts_item_2.node, &object_parts_list); + qs_list_append (&object_parts_item_3.node, &object_parts_list); + input.object_parts = &object_parts_list; + input.upload_id = (char *)contextMultiPartObjectTest->uploadID.c_str(); + QsError err = qs_complete_multipart_upload ((char *) (objectkey.c_str()), &input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR == err) + { + } + qs_release_service(context_hdl); +} + +THEN ("^complete multipart upload status code is (\\d+)$") +{ + REGEX_PARAM (int, expected); + ScenarioScope contextOutput; + release_complete_multipart_upload_output (& (*contextOutput)); + EXPECT_EQ (expected, (int)contextOutput->response_code); +} + +//# Abort Multipart Upload +//When abort multipart upload with key "" +//Then abort multipart upload status code is 400 +WHEN ("^abort multipart upload with key \"(.{1,})\"$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + REGEX_PARAM (std::string, objectkey); + ScenarioScope contextMultiPartObjectTest; + qs_abort_multipart_upload_input_t input; + ScenarioScope contextOutput; + init_abort_multipart_upload_input (&input); + input.upload_id = (char *)contextMultiPartObjectTest->uploadID.c_str(); + QsError err = qs_abort_multipart_upload ((char *) (objectkey.c_str()), &input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR == err) + { + } + qs_release_service(context_hdl); +} + +THEN ("^abort multipart upload status code is (\\d+)$") +{ + REGEX_PARAM (int, expected); + ScenarioScope contextOutput; + release_abort_multipart_upload_output (& (*contextOutput)); + EXPECT_EQ (expected, (int)contextOutput->response_code); +} + +//# DELETE Object +//When delete the multipart object with key "" +//Then delete the multipart object status code is 204 +WHEN ("^delete the multipart object with key \"(.{1,})\"$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + REGEX_PARAM (std::string, objectkey); + qs_delete_object_input_t input; + ScenarioScope contextOutput; + init_delete_object_input (&input); + QsError err = qs_delete_object ((char *) (objectkey.c_str()), &input, & (*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR == err) + { + // print sth + } + qs_release_service(context_hdl); +} + +THEN ("^delete the multipart object status code is (\\d+)$") +{ + REGEX_PARAM (int, expected); + ScenarioScope contextOutput; + release_delete_object_output (& (*contextOutput)); + EXPECT_EQ (expected, (int)contextOutput->response_code); +} diff --git a/test/c_style_tests/CTestService.cpp b/test/c_style_tests/CTestService.cpp new file mode 100644 index 0000000..8d38912 --- /dev/null +++ b/test/c_style_tests/CTestService.cpp @@ -0,0 +1,101 @@ +#include +#include +#include "qingstor/QsList.h" +#include +#include "qingstor/service_with_c_style/QingStorCStyle.h" +#include +#include + +using cucumber::ScenarioScope; + +struct TestBucketCtx +{ + void *pQsService; + void *pQsBucket; +}; +struct TestObjectCtx +{ + void *pQsService; + void *pQsBucket; + std::string bucketName; +}; + +struct TestListMultipartUploadsCtx +{ + void *pQsService; + void *pQsBucket; + std::string bucketName; + std::string objectKey; + std::string uploadID; +}; + + +static char* strConfigPath; + +static char* strBucketName; + +static char* strZone; + +// read necessary information from environment variables. +void init_test_config(void) +{ + // Get QingStor config file path. + strConfigPath = getenv("QINGSTOR_CONFIG_PATH"); + // Get QingStor bucket name. + strBucketName = getenv("QINGSTOR_BUCKET_NAME"); + // Get QingStor zone name. + strZone = getenv("QINGSTOR_ZONE_NAME"); + if(!strConfigPath || !strBucketName || !strZone) + { + printf("Envionment variables are missing : QINGSTOR_CONFIG_PATH or QINGSTOR_BUCKET_NAME or QINGSTOR_ZONE_NAME.\n"); + return; + } + printf("QINGSTOR_CONFIG_PATH: %s.\n",strConfigPath); + printf("QINGSTOR_BUCKET_NAME: %s.\n",strBucketName); + printf("QINGSTOR_ZONE_NAME: %s.\n",strZone); + + qs_init_sdk("/tmp/", Debug, true); +} + +/* +Scenario: need to use QingStor service +When initialize QingStor service +Then the QingStor service is initialized +*/ +WHEN("^initialize QingStor service$") +{ + init_test_config(); +} + +THEN("^the QingStor service is initialized$") +{ + EXPECT_EQ(NULL, NULL); +} + +/* +# GET Service(List Buckets) +Scenario: list all buckets + When list buckets + Then list buckets status code is 200 +*/ +WHEN("^list buckets$") +{ + qs_context_handle context_hdl = qs_create_service_with_configfile(strConfigPath, strBucketName, strZone); + ScenarioScope contextOutput; + qs_list_buckets_input_t input; + init_list_buckets_input(&input); + QsError err = qs_list_buckets(&input, &(*contextOutput), context_hdl); + if (QS_ERR_NO_ERROR != err) + { + // print sth + } + qs_release_service(context_hdl); +} + +THEN("^list buckets status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + release_list_buckets_output(&(*contextOutput)); + EXPECT_EQ(expected, (int)contextOutput->response_code); +} diff --git a/test/c_style_tests/RunTestCStyleAPI.cpp b/test/c_style_tests/RunTestCStyleAPI.cpp new file mode 100644 index 0000000..0cd1315 --- /dev/null +++ b/test/c_style_tests/RunTestCStyleAPI.cpp @@ -0,0 +1,8 @@ +#include "CTestService.cpp" +#include "CTestBucket.cpp" +#include "CTestBucketACL.cpp" +#include "CTestBucketCORS.cpp" +#include "CTestBucketExternalMirror.cpp" +#include "CTestBucketPolicy.cpp" +#include "CTestObject.cpp" +#include "CTestObjectMultipart.cpp" diff --git a/test/cpp_style_tests/CMakeLists.txt b/test/cpp_style_tests/CMakeLists.txt new file mode 100644 index 0000000..730dba0 --- /dev/null +++ b/test/cpp_style_tests/CMakeLists.txt @@ -0,0 +1,15 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) +SET(CUKE_EXTRA_LIBRARIES ${CUKE_EXTRA_LIBRARIES} ${Boost_THREAD_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_REGEX_LIBRARY} ${Boost_DATE_TIME_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_FILESYSTEM_LIBRARY}) +SET(SRC_LIST RunTestCppStyleAPI.cpp) +SET(LIBRARYS_MY /usr/local/lib/libqingstor.so) +SET(LIBRARYS + /usr/local/lib/libgtest.a + /usr/local/lib/libgmock.a + /usr/local/lib/libcucumber-cpp.a + ) + +ADD_EXECUTABLE(RunTestCppStyleAPI ${SRC_LIST}) + +TARGET_LINK_LIBRARIES(RunTestCppStyleAPI ${LIBRARYS} ${LIBRARYS_MY} ${Boost_LIBRARIES}) \ No newline at end of file diff --git a/test/cpp_style_tests/CppTestBucket.cpp b/test/cpp_style_tests/CppTestBucket.cpp new file mode 100644 index 0000000..037f3f5 --- /dev/null +++ b/test/cpp_style_tests/CppTestBucket.cpp @@ -0,0 +1,320 @@ +/* +Scenario: need to use bucket + When initialize the bucket + Then the bucket is initialized +*/ +#include + +WHEN("^initialize the bucket$") +{ + // read necessary information from environment variables. + init_test_config(); + //QingStorService::InitService(strConfigPath.c_str()); + //QingStor::QsConfig qsConfig; + //qsConfig.LoadConfigFile(strConfigPath.c_str()); + ScenarioScope context; + //context->pQsService = new QingStorService(qsConfig); + //context->pQsBucket = new Bucket(qsConfig, strBucketName, strZone); +} + +THEN("^the bucket is initialized$") +{ + //REGEX_PARAM(double, expected); + ScenarioScope context; + EXPECT_EQ(NULL, NULL); +} + +////////////////////////// +///// # PUT Bucket ///// +////////////////////////// +/* +Scenario: create the bucket + When put bucket + Then put bucket status code is 201 +*/ +WHEN("^put bucket$") +{ + // if you are testing on public cloud environment, this scenario should be skiped. + //QingStor::QsConfig qsConfig; + //qsConfig.LoadConfigFile(strConfigPath.c_str()); + //QingStorService qsService(qsConfig); + //Bucket qsBucket = Bucket(qsConfig, strBucketName, strZone); + ////putobject + //PutBucketInput input; + //PutBucketOutput outtput; + //std::stringstream ss; + //std::shared_ptr objectStream = std::make_shared(); + //QsError err = qsBucket.PutBucket(input, outtput); + //if (QS_ERR_NO_ERROR != err) + //{ + // + //} +} + +THEN("^put bucket status code is (\\d+)$") +{ + // if you are testing on public cloud environment, this scenario should be skiped. + REGEX_PARAM(double, expected); + //ScenarioScope contextOutput; + //EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); + EXPECT_EQ(expected, expected); +} + +/* +Scenario: create the same bucket again + When put same bucket again + Then put same bucket again status code is 409 +*/ +WHEN("^put same bucket again$") +{ + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath.c_str()); + Bucket qsBucket = Bucket(qsConfig, strBucketName, strZone); + PutBucketInput input; + ScenarioScope contextOutput; + QsError err = qsBucket.PutBucket(input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } +} + +THEN("^put same bucket again status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, expected); +} + +//////////////////////////////////////// +///// # GET Bucket(List Objects) ///// +//////////////////////////////////////// +/* +Scenario: list objects in the bucket + When list objects + Then list objects status code is 200 + And list objects keys count is 0 +*/ +WHEN("^list objects$") +{ + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath.c_str()); + QingStorService qsService(qsConfig); + Bucket qsBucket = Bucket(qsConfig, strBucketName, strZone); + ListObjectsInput input; + ScenarioScope contextOutput; + QsError err = qsBucket.ListObjects(input, *contextOutput); + if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + ResponseErrorInfo errorInfo = contextOutput->GetResponseErrInfo(); + } +} + +THEN("^list objects status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} + +THEN("^list objects keys count is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + std::vector keys = contextOutput->GetKeys(); + EXPECT_EQ(expected, keys.size()); +} + +/////////////////////////// +///// # Head Bucket ///// +/////////////////////////// +/* +Scenario: head the bucket + When head bucket + Then head bucket status code is 200 +*/ +WHEN("^head bucket$") +{ + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath.c_str()); + QingStorService qsService(qsConfig); + Bucket qsBucket = Bucket(qsConfig, strBucketName, strZone); + HeadBucketInput input; + ScenarioScope contextOutput; + QsError err = qsBucket.HeadBucket(input, *contextOutput); + if (QS_ERR_NO_ERROR == err) + { + } +} + +THEN("^head bucket status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} + +/////////////////////////////////////// +///// # Delete Multiple Objects ///// +/////////////////////////////////////// +/* +Scenario : delete multiple objects in the bucket + When delete multiple objects : + """ + { + "quiet": false, + "objects" : [ + { + "key": "object_0" + }, + { + "key": "object_1" + }, + { + "key": "object_2" + } + ] + } + """ + Then delete multiple objects code is 200 +*/ +WHEN("^delete multiple objects:$") +{ + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath.c_str()); + QingStorService qsService(qsConfig); + Bucket qsBucket = Bucket(qsConfig, strBucketName, strZone); + HeadBucketInput input; + ScenarioScope contextOutput; + QsError err = qsBucket.HeadBucket(input, *contextOutput); + if (QS_ERR_NO_ERROR == err) + { + } +} + +THEN("^delete multiple objects code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} + +///////////////////////////////////// +///// # GET Bucket Statistics ///// +///////////////////////////////////// +/* +Scenario : get statistics of the bucket + When get bucket statistics + Then get bucket statistics status code is 200 + And get bucket statistics status is "active" +*/ +WHEN("^get bucket statistics$") +{ + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath.c_str()); + QingStorService qsService(qsConfig); + Bucket qsBucket = Bucket(qsConfig, strBucketName, strZone); + GetBucketStatisticsInput input; + ScenarioScope contextOutput; + QsError err = qsBucket.GetBucketStatistics(input, *contextOutput); + if (QS_ERR_UNEXCEPTED_RESPONSE == err) + { + ResponseErrorInfo errorInfo = contextOutput->GetResponseErrInfo(); + } +} + +THEN("^get bucket statistics status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} + +THEN("get bucket statistics status is \"([^\"]*)\"$") +{ + REGEX_PARAM(std::string, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, contextOutput->GetStatus()); +} + +///////////////////////////// +///// # DELETE Bucket ///// +///////////////////////////// +/* +Scenario : delete the bucket + When delete bucket + Then delete bucket status code is 204 +*/ +WHEN("^delete bucket$") +{ + // if you are testing on public cloud environment, this scenario should be skiped. +} + +THEN("^delete bucket status code is (\\d+)$") +{ + // if you are testing on public cloud environment, this scenario should be skiped. + REGEX_PARAM(double, expected); + EXPECT_EQ(expected, expected); +} + +////////////////////////////////////// +///// # List Multipart Uploads ///// +////////////////////////////////////// +/* +Scenario : list multipart uploads + Given an object created by initiate multipart upload + When list multipart uploads + Then list multipart uploads count is 1 +*/ + +GIVEN("^an object created by initiate multipart upload$") +{ + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath.c_str()); + QingStorService qsService(qsConfig); + Bucket qsBucket = Bucket(qsConfig, strBucketName, strZone); + ScenarioScope contextGiven; + InitiateMultipartUploadInput input; + InitiateMultipartUploadOutput output; + contextGiven->objectKey = "testInitMultipartUpload.txt"; + QsError err = qsBucket.InitiateMultipartUpload(contextGiven->objectKey, input, output); + if (QS_ERR_NO_ERROR == err) + { + contextGiven->uploadID = output.GetUploadID(); + } + UploadMultipartInput multipartInput; + UploadMultipartOutput multipartOutput; + std::iostream* objectStream = new std::stringstream(); + *objectStream << " |this is a Part 1| "; + objectStream->flush(); + multipartInput.SetBody(objectStream); + multipartInput.SetContentLength(strlen(" |this is a Part 1| ")); + multipartInput.SetPartNumber(1); + multipartInput.SetUploadID(contextGiven->uploadID); + err = qsBucket.UploadMultipart(contextGiven->objectKey, multipartInput, multipartOutput); + if (QS_ERR_NO_ERROR == err) + { + } + delete objectStream; +} + +WHEN("^list multipart uploads$") +{ + ScenarioScope contextGiven; + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath.c_str()); + QingStorService qsService(qsConfig); + Bucket qsBucket = Bucket(qsConfig, strBucketName, strZone); + ListMultipartUploadsInput input; + ScenarioScope contextOutput; + QsError err = qsBucket.ListMultipartUploads(input, *contextOutput); + if (QS_ERR_NO_ERROR == err) + { + } +} + +THEN("^list multipart uploads count is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, contextOutput->GetUploads().size()); +} diff --git a/test/cpp_style_tests/CppTestBucketACL.cpp b/test/cpp_style_tests/CppTestBucketACL.cpp new file mode 100644 index 0000000..a32ec10 --- /dev/null +++ b/test/cpp_style_tests/CppTestBucketACL.cpp @@ -0,0 +1,94 @@ +//Feature: the bucket ACL feature + +////////////////////////////// +///// # PUT Bucket ACL ///// +////////////////////////////// + +//Scenario: set the bucket ACL +//When put bucket ACL: +// """ +// { +// "acl": [ +// { +// "grantee": { +// "type": "group", +// "name" : "QS_ALL_USERS" +// }, +// "permission" : "FULL_CONTROL" +// } +// ] +// } +// """ +//Then put bucket ACL status code is 200 +WHEN("^put bucket ACL:$") +{ + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath.c_str()); + QingStorService qsService(qsConfig); + Bucket qsBucket = Bucket(qsConfig, strBucketName, strZone); + PutBucketACLInput input; + ScenarioScope contextOutput; + std::vector aclList; + ACLType acl; + GranteeType grantee; + //grantee.SetID("1"); + grantee.SetType("group"); + grantee.SetName("QS_ALL_USERS"); + acl.SetGrantee(grantee); + acl.SetPermission("FULL_CONTROL"); + aclList.push_back(acl); + input.SetACL(aclList); + QsError err = qsBucket.PutBucketACL(input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } +} + +THEN("^put bucket ACL status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} + +////////////////////////////// +///// # GET Bucket ACL ///// +////////////////////////////// +/* +Scenario : get ACL of the bucket +When get bucket ACL +Then get bucket ACL status code is 200 +And get bucket ACL should have grantee name "QS_ALL_USERS" +*/ +WHEN("^get bucket ACL$") +{ + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath.c_str()); + QingStorService qsService(qsConfig); + Bucket qsBucket = Bucket(qsConfig, strBucketName, strZone); + GetBucketACLInput input; + ScenarioScope contextOutput; + QsError err = qsBucket.GetBucketACL(input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } +} + +THEN("^get bucket ACL status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} + +THEN("^get bucket ACL should have grantee name \"([^\"]*)\"$") +{ + REGEX_PARAM(std::string, expected); + ScenarioScope contextOutput; + std::string granteeName = ""; + if (contextOutput->GetACL().size()) + { + granteeName = contextOutput->GetACL().at(1).GetGrantee().GetName(); + } + EXPECT_EQ(expected, granteeName); +} diff --git a/test/cpp_style_tests/CppTestBucketCORS.cpp b/test/cpp_style_tests/CppTestBucketCORS.cpp new file mode 100644 index 0000000..062c830 --- /dev/null +++ b/test/cpp_style_tests/CppTestBucketCORS.cpp @@ -0,0 +1,167 @@ +//////////Feature: the bucket CORS feature + +/////////////////////////////// +///// # PUT Bucket CORS ///// +/////////////////////////////// +//Scenario : set the bucket CORS +// When put bucket CORS : +// """ +// { +// "cors_rules": [ +// { +// "allowed_origin": "http://*.qingcloud.com", +// "allowed_methods" : [ +// "PUT", +// "GET", +// "DELETE", +// "POST" +// ], +// "allowed_headers": [ +// "X-QS-Date", +// "Content-Type", +// "Content-MD5", +// "Authorization" +// ], +// "max_age_seconds": 200, +// "expose_headers" : [ +// "X-QS-Date" +// ] +// }, +// { +// "allowed_origin": "http://*.example.com", +// "allowed_methods" : [ +// "PUT", +// "GET", +// "DELETE", +// "POST" +// ], +// "allowed_headers": [ +// "*" +// ], +// "max_age_seconds" : 400 +// } +// ] +// } +// """ +// Then put bucket CORS status code is 200 +WHEN("^put bucket CORS:$") +{ + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath); + QingStorService qsService(qsConfig); + Bucket qsBucket = Bucket(qsConfig, strBucketName, strZone); + PutBucketCORSInput input; + ScenarioScope contextOutput; + std::vector rules; + CORSRuleType rule1; + CORSRuleType rule2; + std::vector allowedMethods; + allowedMethods.push_back("PUT"); + allowedMethods.push_back("GET"); + allowedMethods.push_back("DELETE"); + allowedMethods.push_back("POST"); + std::vector allowedHeaders; + allowedHeaders.push_back("X-QS-Date"); + allowedHeaders.push_back("Content-Type"); + allowedHeaders.push_back("Content-MD5"); + allowedHeaders.push_back("Authorization"); + std::vector allowedAllHeaders; + allowedAllHeaders.push_back("*"); + std::vector exposeHeaders; + exposeHeaders.push_back("X-QS-Date"); + rule1.SetAllowedOrigin("http://*.qingcloud.com"); + rule1.SetAllowedMethods(allowedMethods); + rule1.SetExposeHeaders(exposeHeaders); + rule1.SetAllowedHeaders(allowedHeaders); + rule1.SetMaxAgeSeconds(200); + rule2.SetAllowedOrigin("http://*.example.com"); + rule2.SetAllowedMethods(allowedMethods); + rule2.SetAllowedHeaders(allowedAllHeaders); + rule2.SetMaxAgeSeconds(400); + rules.push_back(rule1); + rules.push_back(rule2); + input.SetCORSRules(rules); + QsError err = qsBucket.PutBucketCORS(input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } +} + +THEN("^put bucket CORS status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} + +/////////////////////////////// +///// # GET Bucket CORS ///// +/////////////////////////////// +/* +Scenario : get CORS of the bucket + When get bucket CORS + Then get bucket CORS status code is 200 + And get bucket CORS should have allowed origin "http://*.qingcloud.com" +*/ +WHEN("^get bucket CORS$") +{ + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath); + QingStorService qsService(qsConfig); + Bucket qsBucket = Bucket(qsConfig, strBucketName, strZone); + GetBucketCORSInput input; + ScenarioScope contextOutput; + QsError err = qsBucket.GetBucketCORS(input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } +} + +THEN("^get bucket CORS status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} + +THEN("^get bucket CORS should have allowed origin \"([^\"]*)\"$") +{ + REGEX_PARAM(std::string, expected); + ScenarioScope contextOutput; + std::string allowedOrigin = ""; + if (contextOutput->GetCORSRules().size()) + { + CORSRuleType corsRule = contextOutput->GetCORSRules().at(0); + allowedOrigin = corsRule.GetAllowedOrigin(); + } + EXPECT_EQ(expected, allowedOrigin); +} + +////////////////////////////////// +///// # DELETE Bucket CORS ///// +////////////////////////////////// +/* +Scenario : delete CORS of the bucket + When delete bucket CORS + Then delete bucket CORS status code is 204 +*/ +WHEN("^delete bucket CORS$") +{ + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath); + QingStorService qsService(qsConfig); + Bucket qsBucket = Bucket(qsConfig, strBucketName, strZone); + DeleteBucketCORSInput input; + ScenarioScope contextOutput; + QsError err = qsBucket.DeleteBucketCORS(input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } +} + +THEN("^delete bucket CORS status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} \ No newline at end of file diff --git a/test/cpp_style_tests/CppTestBucketExternalMirror.cpp b/test/cpp_style_tests/CppTestBucketExternalMirror.cpp new file mode 100644 index 0000000..30d75e6 --- /dev/null +++ b/test/cpp_style_tests/CppTestBucketExternalMirror.cpp @@ -0,0 +1,103 @@ + +///// Feature: the bucket external mirror feature + +//////////////////////////////////////////// +///// # PUT Bucket External Mirror ///// +//////////////////////////////////////////// +/* +Scenario : set the bucket external mirror + When put bucket external mirror : + """ + { + "source_site": "https://example.com/something/" + } + """ + Then put bucket external mirror status code is 200 +*/ +WHEN("^put bucket external mirror:$") +{ + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath.c_str()); + QingStorService qsService(qsConfig); + Bucket qsBucket = Bucket(qsConfig, strBucketName, strZone); + PutBucketExternalMirrorInput input; + ScenarioScope contextOutput; + input.SetSourceSite("https://example.com/something/"); + QsError err = qsBucket.PutBucketExternalMirror(input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } +} + +THEN("^put bucket external mirror status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} + +//////////////////////////////////////////// +///// # GET Bucket External Mirror ///// +//////////////////////////////////////////// +/* +Scenario : get external mirror of the bucket + When get bucket external mirror + Then get bucket external mirror status code is 200 + And get bucket external mirror should have source_site "https://example.com/something/" +*/ +WHEN("^get bucket external mirror$") +{ + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath.c_str()); + QingStorService qsService(qsConfig); + Bucket qsBucket = Bucket(qsConfig, strBucketName, strZone); + GetBucketExternalMirrorInput input; + ScenarioScope contextOutput; + QsError err = qsBucket.GetBucketExternalMirror(input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } +} + +THEN("^get bucket external mirror status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} + +THEN("^get bucket external mirror should have source_site \"([^\"]*)\"$") +{ + REGEX_PARAM(std::string, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, contextOutput->GetSourceSite()); +} + +/////////////////////////////////////////////// +///// # DELETE Bucket External Mirror ///// +/////////////////////////////////////////////// +/* +Scenario : delete external mirror of the bucket + When delete bucket external mirror + Then delete bucket external mirror status code is 204 +*/ +WHEN("^delete bucket external mirror$") +{ + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath.c_str()); + QingStorService qsService(qsConfig); + Bucket qsBucket = Bucket(qsConfig, strBucketName, strZone); + DeleteBucketExternalMirrorInput input; + ScenarioScope contextOutput; + QsError err = qsBucket.DeleteBucketExternalMirror(input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } +} + +THEN("^delete bucket external mirror status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} \ No newline at end of file diff --git a/test/cpp_style_tests/CppTestBucketPolicy.cpp b/test/cpp_style_tests/CppTestBucketPolicy.cpp new file mode 100644 index 0000000..cb7a5bf --- /dev/null +++ b/test/cpp_style_tests/CppTestBucketPolicy.cpp @@ -0,0 +1,182 @@ +//// Feature: the bucket policy feature + +////////////////////////////////// +///// # PUT Bucket policy ///// +////////////////////////////////// +/* +Scenario : set the bucket policy + # Notice : Please set statement resource manually + When put bucket policy : + """ + { + "statement": [ + { + "id": "allow certain site to get objects", + "user" : [ + "*" + ], + "action" : [ + "get_object" + ], + "effect" : "allow", + "resource" : [], + "condition" : { + "string_like": { + "Referer": [ + "*.example1.com", + "*.example2.com" + ] + }, + "ip_address": { + "source_ip": [ + "172.16.0.0/24", + "172.16.1.1/32" + ] + } + } + } + ] + } + """ + Then put bucket policy status code is 200 +*/ +WHEN("^put bucket policy:$") +{ + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath.c_str()); + QingStorService qsService(qsConfig); + Bucket qsBucket = Bucket(qsConfig, strBucketName, strZone); + PutBucketPolicyInput input; + ScenarioScope contextOutput; + std::vector < StatementType > statementVec; + StatementType statement; + // set ID + statement.SetID("allow certain site to get objects"); + // set user + std::vector < std::string > userVec; + userVec.push_back("*"); + statement.SetUser(userVec); + // set action + std::vector < std::string > actionVec; + actionVec.push_back("get_object"); + statement.SetAction(actionVec); + // set effect + statement.SetEffect("allow"); + // set resource + std::string resource = strBucketName + "/*"; + std::vector < std::string > resourceVec; + resourceVec.push_back(resource); + statement.SetResource(resourceVec); + // set condition + ConditionType condition; + // set condition stringlike + StringLikeType stringLike; + std::vector < std::string > referer; + referer.push_back("*.example1.com"); + referer.push_back("*.example2.com"); + stringLike.SetReferer(referer); + condition.SetStringLike(stringLike); + //set condition ip_address + std::vector < std::string > sourceIPVec; + sourceIPVec.push_back("172.16.0.0/24"); + sourceIPVec.push_back("172.16.1.1/32"); + IPAddressType ipAddress; + ipAddress.SetSourceIP(sourceIPVec); + condition.SetIPAddress(ipAddress); + statement.SetCondition(condition); + statementVec.push_back(statement); + input.SetStatement(statementVec); + QsError err = qsBucket.PutBucketPolicy(input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } +} + +THEN("^put bucket policy status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} + +////////////////////////////////// +///// # GET Bucket policy ///// +////////////////////////////////// +/* +Scenario : get policy of the bucket + When get bucket policy + Then get bucket policy status code is 200 + And get bucket policy should have Referer "*.example1.com" +*/ +WHEN("^get bucket policy$") +{ + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath.c_str()); + QingStorService qsService(qsConfig); + Bucket qsBucket = Bucket(qsConfig, strBucketName, strZone); + GetBucketPolicyInput input; + ScenarioScope contextOutput; + QsError err = qsBucket.GetBucketPolicy(input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } +} + +THEN("^get bucket policy status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} + +THEN("^get bucket policy should have Referer \"([^\"]*)\"$") +{ + REGEX_PARAM(std::string, expected); + ScenarioScope contextOutput; + ConditionType condition; + StringLikeType striinglike; + std::vector refererList; + std::string referer = ""; + std::vector statementList = contextOutput->GetStatement(); + if (statementList.size()) + { + StatementType statement = statementList.at(0); + condition = statement.GetCondition(); + striinglike = condition.GetStringLike(); + refererList = striinglike.GetReferer(); + if (refererList.size()) + { + referer = refererList.at(0); + } + } + EXPECT_EQ(expected, referer); +} + +////////////////////////////////// +///// # DELETE Bucket policy ///// +////////////////////////////////// +/* +Scenario : delete policy of the bucket + When delete bucket policy + Then delete bucket policy status code is 204 +*/ +WHEN("^delete bucket policy$") +{ + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath); + QingStorService qsService(qsConfig); + Bucket qsBucket = Bucket(qsConfig, strBucketName, strZone); + DeleteBucketPolicyInput input; + ScenarioScope contextOutput; + QsError err = qsBucket.DeleteBucketPolicy(input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } +} + +THEN("^delete bucket policy status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} \ No newline at end of file diff --git a/test/cpp_style_tests/CppTestObject.cpp b/test/cpp_style_tests/CppTestObject.cpp new file mode 100644 index 0000000..326cca4 --- /dev/null +++ b/test/cpp_style_tests/CppTestObject.cpp @@ -0,0 +1,272 @@ +//// Feature: the object feature + +// Scenario Outline : +// # PUT Object +// When put object with key "" +// Then put object status code is 201 +WHEN("^put object with key \"(.{1,})\"$") +{ + REGEX_PARAM(std::string, objectKey); + ScenarioScope contextObjectTest; + contextObjectTest->bucketName = strBucketName; + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath); + contextObjectTest->pQsBucket = new Bucket(qsConfig, strBucketName, strZone); + Bucket qsBucket = *contextObjectTest->pQsBucket; + PutObjectInput input; + ScenarioScope contextOutput; + std::iostream* objectStream = new std::stringstream(); + *objectStream << "thi is a test"; + objectStream->flush(); + input.SetContentLength(strlen("thi is a test")); + input.SetBody(objectStream); + QsError err = qsBucket.PutObject(objectKey, input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } + if(objectStream) + delete objectStream; +} + +THEN("^put object status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} + +//# Copy Object +//When copy object with key "" +//Then copy object status code is 201 +WHEN("^copy object with key \"(.{1,})\"$") +{ + REGEX_PARAM(std::string, objectkeyFromSource); + std::string objectkeyTopPut = objectkeyFromSource + "_copy"; + ScenarioScope contextObjectTest; + std::string sourcePrefix = "/" + contextObjectTest->bucketName + "/"; + Bucket qsBucket = *contextObjectTest->pQsBucket; + PutObjectInput input; + ScenarioScope contextOutput; + input.SetXQSCopySource(sourcePrefix + objectkeyFromSource); + input.SetContentLength(0); + QsError err = qsBucket.PutObject(objectkeyTopPut, input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } +} + +THEN("^copy object status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} + +//# Move Object +//When move object with key "" +//Then move object status code is 201 +WHEN("^move object with key \"(.{1,})\"$") +{ + REGEX_PARAM(std::string, objectkey); + std::string objectkeySrc = objectkey + "_copy"; + std::string objectkeyDest = objectkey + "_move"; + ScenarioScope contextObjectTest; + std::string sourcePrefix = "/" + contextObjectTest->bucketName + "/"; + Bucket qsBucket = *contextObjectTest->pQsBucket; + PutObjectInput input; + ScenarioScope contextOutput; + input.SetXQSMoveSource(sourcePrefix + objectkeySrc); + input.SetContentLength(0); + QsError err = qsBucket.PutObject(objectkeyDest, input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } +} + +THEN("^move object status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} + +//# GET Object +//When get object with key "" +//Then get object status code is 200 +//And get object content length is 1048576 +WHEN("^get object with key \"(.{1,})\"$") +{ + REGEX_PARAM(std::string, objectkeyToGet); + ScenarioScope contextObjectTest; + Bucket qsBucket = *contextObjectTest->pQsBucket; + GetObjectInput input; + ScenarioScope contextOutput; + QsError err = qsBucket.GetObject(objectkeyToGet, input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } +} + +THEN("^get object status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} + +THEN("^get object content length is (\\d+)$") +{ + REGEX_PARAM(double, expected); + (void)expected; + ScenarioScope contextOutput; + std::iostream* objectStream = contextOutput->GetBody(); + objectStream->seekg(0, contextOutput->GetBody()->end); + size_t streamSize = objectStream->tellg(); + delete objectStream; + int objectLen = static_cast(streamSize); + int exceptedLen = strlen("thi is a test"); + EXPECT_EQ(exceptedLen, objectLen); +} + +//# GET Object with Content - Type +//When get object "" with content type "video/mp4; charset=utf8" +//Then get object content type is "video/mp4; charset=utf8" +WHEN("^get object \"(.{1,})\" with content type \"(.{1,})\"$") +{ + REGEX_PARAM(std::string, objectkey); + ScenarioScope contextObjectTest; +} + +THEN("^get object content type is \"(.{1,})\"$") +{ + REGEX_PARAM(std::string, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, "video/mp4; charset=utf8"); +} + +//# GET Object with Query Signature +//When get object "" with query signature +//Then get object with query signature content length is 1048576 +WHEN("^get object \"(.{1,})\" with query signature$") +{ + REGEX_PARAM(std::string, objectkey); + ScenarioScope contextObjectTest; + Bucket qsBucket = *contextObjectTest->pQsBucket; + GetObjectInput input; + ScenarioScope contextOutput; + QsError err = qsBucket.GetObject(objectkey, input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } +} + +THEN("^get object with query signature content length is (\\d+)$") +{ + REGEX_PARAM(std::string, expected); + ScenarioScope contextOutput; + size_t streamSize = 0; + std::iostream* objectStream = contextOutput->GetBody(); + if(objectStream) + { + objectStream->seekg(0, objectStream->end); + streamSize = objectStream->tellg(); + delete objectStream; + } + int exceptedLen = strlen("thi is a test"); + EXPECT_EQ(exceptedLen, static_cast(streamSize)); +} + +//# Head Object +//When head object with key "" +//Then head object status code is 200 +WHEN("^head object with key \"(.{1,})\"$") +{ + REGEX_PARAM(std::string, objectkey); + ScenarioScope contextObjectTest; + Bucket qsBucket = *contextObjectTest->pQsBucket; + HeadObjectInput input; + ScenarioScope contextOutput; + QsError err = qsBucket.HeadObject(objectkey, input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } +} + +THEN("^head object status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} + +//# Options Object +//When options object "" with method "GET" and origin "qingcloud.com" +//Then options object status code is 200 +WHEN("^options object \"(.{1,})\" with method \"([^\"]*)\" and origin \"([^\"]*)\"$") +{ + REGEX_PARAM(std::string, objectkey); + ScenarioScope contextObjectTest; + Bucket qsBucket = *contextObjectTest->pQsBucket; + OptionsObjectInput input; + ScenarioScope contextOutput; + input.SetAccessControlRequestMethod("GET"); + input.SetOrigin("qingcloud.com"); + QsError err = qsBucket.OptionsObject(objectkey, input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } +} + +THEN("^options object status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} + +//# DELETE Object +//When delete object with key "" +//Then delete object status code is 204 +//When delete the move object with key "" +//Then delete the move object status code is 204 +WHEN("^delete object with key \"(.{1,})\"$") +{ + REGEX_PARAM(std::string, objectkey); + ScenarioScope contextObjectTest; + Bucket qsBucket = *contextObjectTest->pQsBucket; + DeleteObjectInput input; + ScenarioScope contextOutput; + QsError err = qsBucket.DeleteObject(objectkey, input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } +} + +THEN("^delete object status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (int)contextOutput->GetResponseCode()); +} + +WHEN("delete the move object with key \"(.{1,})\"$") +{ + REGEX_PARAM(std::string, objectkey); + std::string objectkeyToDel = objectkey + "_move"; + ScenarioScope contextObjectTest; + Bucket qsBucket = *contextObjectTest->pQsBucket; + DeleteObjectInput input; + ScenarioScope contextOutput; + QsError err = qsBucket.DeleteObject(objectkeyToDel, input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } + delete contextObjectTest->pQsBucket; +} + +THEN("^delete the move object status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (double)contextOutput->GetResponseCode()); +} diff --git a/test/cpp_style_tests/CppTestObjectMultipart.cpp b/test/cpp_style_tests/CppTestObjectMultipart.cpp new file mode 100644 index 0000000..5a4d1bf --- /dev/null +++ b/test/cpp_style_tests/CppTestObjectMultipart.cpp @@ -0,0 +1,243 @@ +static std::iostream* Create5MbStream4UploadPart(const std::string partTag) +{ + uint32_t fiveMbSize = 5 * 1024 * 1024; + std::stringstream patternStream; + patternStream << "Multi-Part upload Test Part " << partTag << ":" << std::endl; + std::string pattern = patternStream.str(); + std::string scratchString; + scratchString.reserve(fiveMbSize); + // 5MB is a hard minimum for multi part uploads; make sure the final string is at least that long + uint32_t patternCopyCount = static_cast< uint32_t >( fiveMbSize / pattern.size() + 1 ); + for(uint32_t i = 0; i < patternCopyCount; ++i) + { + scratchString.append(pattern); + } + std::iostream* streamPtr = new std::stringstream(scratchString); + streamPtr->seekg(0); + streamPtr->seekp(0, std::ios_base::end); + return streamPtr; +} + +//Scenario Outline : +//# Initiate Multipart Upload +//When initiate multipart upload with key "" +//Then initiate multipart upload status code is 200 +WHEN ("^initiate multipart upload with key \"(.{1,})\"$") +{ + REGEX_PARAM (std::string, objectkey); + ScenarioScope contextMultiPartObjectTest; + contextMultiPartObjectTest->bucketName = strBucketName; + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile (strConfigPath); + contextMultiPartObjectTest->pQsBucket = new Bucket (qsConfig, strBucketName, strZone); + Bucket qsBucket = *contextMultiPartObjectTest->pQsBucket; + InitiateMultipartUploadInput input; + ScenarioScope contextOutput; + QsError err = qsBucket.InitiateMultipartUpload (objectkey, input, *contextOutput); + if (QS_ERR_NO_ERROR == err) + { + contextMultiPartObjectTest->uploadID = contextOutput->GetUploadID(); + } +} +THEN ("^initiate multipart upload status code is (\\d+)$") +{ + REGEX_PARAM (double, expected); + ScenarioScope contextOutput; + EXPECT_EQ (expected, (double)contextOutput->GetResponseCode()); +} + +//# Upload Multipart +//When upload the first part with key "" +//Then upload the first part status code is 201 +//When upload the second part with key "" +//Then upload the second part status code is 201 +//When upload the third part with key "" +//Then upload the third part status code is 201 +WHEN ("^upload the first part with key \"(.{1,})\"$") +{ + REGEX_PARAM (std::string, objectkey); + ScenarioScope contextMultiPartObjectTest; + Bucket qsBucket = *contextMultiPartObjectTest->pQsBucket; + UploadMultipartInput input; + ScenarioScope contextOutput; + std::iostream* objectStream = Create5MbStream4UploadPart("1"); + objectStream->seekg(0, objectStream->end); + size_t streamSize = objectStream->tellg(); + objectStream->seekg(0, objectStream->beg); + input.SetContentLength(streamSize); + input.SetBody (objectStream); + input.SetPartNumber (1); + input.SetUploadID (contextMultiPartObjectTest->uploadID); + QsError err = qsBucket.UploadMultipart (objectkey, input, *contextOutput); + if (QS_ERR_NO_ERROR == err) + { + } + delete objectStream; +} +THEN ("^upload the first part status code is (\\d+)$") +{ + REGEX_PARAM (double, expected); + ScenarioScope contextOutput; + EXPECT_EQ (expected, (double)contextOutput->GetResponseCode()); +} + +WHEN ("^upload the second part with key \"(.{1,})\"$") +{ + REGEX_PARAM (std::string, objectkey); + ScenarioScope contextMultiPartObjectTest; + Bucket qsBucket = *contextMultiPartObjectTest->pQsBucket; + UploadMultipartInput input; + ScenarioScope contextOutput; + std::iostream* objectStream = Create5MbStream4UploadPart("2"); + objectStream->seekg(0, objectStream->end); + size_t streamSize = objectStream->tellg(); + objectStream->seekg(0, objectStream->beg); + input.SetContentLength(streamSize); + input.SetBody (objectStream); + input.SetPartNumber (2); + input.SetUploadID (contextMultiPartObjectTest->uploadID); + QsError err = qsBucket.UploadMultipart (objectkey, input, *contextOutput); + if (QS_ERR_NO_ERROR == err) + { + } + delete objectStream; +} +THEN ("^upload the second part status code is (\\d+)$") +{ + REGEX_PARAM (double, expected); + ScenarioScope contextOutput; + EXPECT_EQ (expected, (double)contextOutput->GetResponseCode()); +} +WHEN ("^upload the third part with key \"(.{1,})\"$") +{ + REGEX_PARAM (std::string, objectkey); + ScenarioScope contextMultiPartObjectTest; + Bucket qsBucket = *contextMultiPartObjectTest->pQsBucket; + UploadMultipartInput input; + ScenarioScope contextOutput; + std::iostream* objectStream = Create5MbStream4UploadPart("3"); + objectStream->seekg(0, objectStream->end); + size_t streamSize = objectStream->tellg(); + objectStream->seekg(0, objectStream->beg); + input.SetContentLength(streamSize); + input.SetBody (objectStream); + input.SetPartNumber (3); + input.SetUploadID (contextMultiPartObjectTest->uploadID); + QsError err = qsBucket.UploadMultipart (objectkey, input, *contextOutput); + if (QS_ERR_NO_ERROR == err) + { + } + delete objectStream; +} +THEN ("^upload the third part status code is (\\d+)$") +{ + REGEX_PARAM (double, expected); + ScenarioScope contextOutput; + EXPECT_EQ (expected, (double)contextOutput->GetResponseCode()); +} + +//# List Multipart +//When list multipart with key "" +//Then list multipart status code is 200 +//And list multipart object parts count is 3 +WHEN ("^list multipart with key \"(.{1,})\"$") +{ + REGEX_PARAM (std::string, objectkey); + ScenarioScope contextMultiPartObjectTest; + Bucket qsBucket = *contextMultiPartObjectTest->pQsBucket; + ListMultipartInput input; + ScenarioScope contextOutput; + input.SetUploadID (contextMultiPartObjectTest->uploadID); + QsError err = qsBucket.ListMultipart (objectkey, input, *contextOutput); + if (QS_ERR_NO_ERROR == err) + { + contextMultiPartObjectTest->objectParts = contextOutput->GetObjectParts(); + } +} + +THEN ("^list multipart status code is (\\d+)$") +{ + REGEX_PARAM (double, expected); + ScenarioScope contextOutput; + EXPECT_EQ (expected, (double)contextOutput->GetResponseCode()); +} + +THEN ("^list multipart object parts count is (\\d+)$") +{ + REGEX_PARAM (double, expected); + ScenarioScope contextOutput; + EXPECT_EQ (expected, (double)contextOutput->GetCount()); +} + +//# Complete Multipart Upload +//When complete multipart upload with key "" +//Then complete multipart upload status code is 201 +WHEN ("^complete multipart upload with key \"(.{1,})\"$") +{ + REGEX_PARAM (std::string, objectkey); + ScenarioScope contextMultiPartObjectTest; + Bucket qsBucket = *contextMultiPartObjectTest->pQsBucket; + CompleteMultipartUploadInput input; + ScenarioScope contextOutput; + input.SetUploadID (contextMultiPartObjectTest->uploadID); + input.SetObjectParts(contextMultiPartObjectTest->objectParts); + QsError err = qsBucket.CompleteMultipartUpload (objectkey, input, *contextOutput); + if (QS_ERR_NO_ERROR == err) + { + } +} + +THEN ("^complete multipart upload status code is (\\d+)$") +{ + REGEX_PARAM (double, expected); + ScenarioScope contextOutput; + EXPECT_EQ (expected, (double)contextOutput->GetResponseCode()); +} + +//# Abort Multipart Upload +//When abort multipart upload with key "" +//Then abort multipart upload status code is 400 +WHEN ("^abort multipart upload with key \"(.{1,})\"$") +{ + REGEX_PARAM (std::string, objectkey); + ScenarioScope contextMultiPartObjectTest; + Bucket qsBucket = *contextMultiPartObjectTest->pQsBucket; + AbortMultipartUploadInput input; + ScenarioScope contextOutput; + input.SetUploadID (contextMultiPartObjectTest->uploadID); + QsError err = qsBucket.AbortMultipartUpload (objectkey, input, *contextOutput); + if (QS_ERR_NO_ERROR == err) + { + } +} + +THEN ("^abort multipart upload status code is (\\d+)$") +{ + REGEX_PARAM (double, expected); + ScenarioScope contextOutput; + EXPECT_EQ (expected, (double)contextOutput->GetResponseCode()); +} + +//# DELETE Object +//When delete the multipart object with key "" +//Then delete the multipart object status code is 204 +WHEN ("^delete the multipart object with key \"(.{1,})\"$") +{ + REGEX_PARAM (std::string, objectkey); + ScenarioScope contextMultiPartObjectTest; + Bucket qsBucket = *contextMultiPartObjectTest->pQsBucket; + DeleteObjectInput input; + ScenarioScope contextOutput; + QsError err = qsBucket.DeleteObject(objectkey, input, *contextOutput); + if (QS_ERR_NO_ERROR == err) + { + } + delete contextMultiPartObjectTest->pQsBucket; +} + +THEN ("^delete the multipart object status code is (\\d+)$") +{ + REGEX_PARAM (double, expected); + ScenarioScope contextOutput; + EXPECT_EQ (expected, (double)contextOutput->GetResponseCode()); +} diff --git a/test/cpp_style_tests/CppTestService.cpp b/test/cpp_style_tests/CppTestService.cpp new file mode 100644 index 0000000..981c230 --- /dev/null +++ b/test/cpp_style_tests/CppTestService.cpp @@ -0,0 +1,116 @@ +#include +#include +#include +#include + +#include +#include + +using cucumber::ScenarioScope; + +using namespace QingStor; + +struct TestObjectCtx +{ + QingStorService *pQsService; + Bucket *pQsBucket; + std::string bucketName; +}; + +struct TestMultipartUploadCtx +{ + QingStorService *pQsService; + Bucket *pQsBucket; + std::string bucketName; + std::string objectKey; + std::string uploadID; + std::vector objectParts; +}; + +struct TestBucketCtx +{ + QingStorService *pQsService; + Bucket *pQsBucket; +}; + +struct TestListMultipartUploadsCtx +{ + QingStorService *pQsService; + Bucket *pQsBucket; + std::string bucketName; + std::string objectKey; + std::string uploadID; +}; + + +static std::string strConfigPath; + +static std::string strBucketName; + +static std::string strZone; + +// read necessary information from environment variables. +void init_test_config(void) +{ + char *configPath = getenv("QINGSTOR_CONFIG_PATH"); + char *bucketName = getenv("QINGSTOR_BUCKET_NAME"); + char *zone = getenv("QINGSTOR_ZONE_NAME"); + if(!configPath || !bucketName || !zone) + { + printf("Envionment variables are missing : QINGSTOR_CONFIG_PATH or QINGSTOR_BUCKET_NAME or QINGSTOR_ZONE_NAME.\n"); + return; + } + printf("QINGSTOR_CONFIG_PATH: %s.\n",configPath); + printf("QINGSTOR_BUCKET_NAME: %s.\n",bucketName); + printf("QINGSTOR_ZONE_NAME: %s.\n",zone); + + strConfigPath = configPath; + strBucketName = bucketName; + strZone = zone; + + QingStor::SDKOptions sdkOptions; + sdkOptions.logLevel = Verbose; + sdkOptions.logPath = "/tmp/"; + InitializeSDK(sdkOptions); +} + +/* +Scenario: need to use QingStor service +When initialize QingStor service +Then the QingStor service is initialized +*/ +WHEN("^initialize QingStor service$") +{ + init_test_config(); +} + +THEN("^the QingStor service is initialized$") +{ + EXPECT_EQ(NULL, NULL); +} + +/* +# GET Service(List Buckets) +Scenario: list all buckets + When list buckets + Then list buckets status code is 200 +*/ +WHEN("^list buckets$") +{ + QingStor::QsConfig qsConfig; + qsConfig.LoadConfigFile(strConfigPath.c_str()); + QingStorService qsService(qsConfig); + ListBucketsInput input; + ScenarioScope contextOutput; + QsError err = qsService.ListBuckets(input, *contextOutput); + if (QS_ERR_NO_ERROR != err) + { + } +} + +THEN("^list buckets status code is (\\d+)$") +{ + REGEX_PARAM(double, expected); + ScenarioScope contextOutput; + EXPECT_EQ(expected, (double)contextOutput->GetResponseCode()); +} \ No newline at end of file diff --git a/test/cpp_style_tests/RunTestCppStyleAPI.cpp b/test/cpp_style_tests/RunTestCppStyleAPI.cpp new file mode 100644 index 0000000..4894b1c --- /dev/null +++ b/test/cpp_style_tests/RunTestCppStyleAPI.cpp @@ -0,0 +1,8 @@ +#include "CppTestService.cpp" +#include "CppTestBucket.cpp" +#include "CppTestBucketACL.cpp" +#include "CppTestBucketCORS.cpp" +#include "CppTestBucketExternalMirror.cpp" +#include "CppTestBucketPolicy.cpp" +#include "CppTestObject.cpp" +#include "CppTestObjectMultipart.cpp" diff --git a/test/features b/test/features new file mode 160000 index 0000000..7a10c59 --- /dev/null +++ b/test/features @@ -0,0 +1 @@ +Subproject commit 7a10c59c11aba4cf2325d97dbf8462b5cd656232